feat: aulas experimentais guardadas, anti-spam partilhado nos formulários, audit das escritas
- Pedido de aula experimental passa a ficar em trial_leads (por ginásio) ANTES do email: sem SMTP o visitante já não vê «erro» e o pedido não se perde. Gestão → Aulas experimentais: estados, notas, CSV (auditado), apagar para a lixeira; aviso «sem email» quando o aviso não saiu. - Aula experimental, inscrição e eventos usam o anti-spam do platform-tools (honeypot, carimbo assinado com tempo mínimo, prova de JS, limite por IP, pontuação de conteúdo) e o bloqueio de IP, em vez de honeypots locais. Recusas ficam em blocked_submissions; resposta igual à de sucesso. Falha aberto se o módulo rebentar. - Checkbox de consentimento da aula experimental passa a ser guardada. - Audit das escritas de conteúdo: criar/editar equipa, modalidades, eventos, mensalidades, pedidos de inscrição, galerias, horário (incl. arrastar no calendário), horas, contactos e ginásios, com antes/depois campo a campo (audit_row/audit_change). Exportação CSV de inscrições auditada. - .table-responsive em todas as tabelas do backoffice. - Migração: database/migration_20260926_trial_leads.sql (só cria tabelas). Testado numa cópia da BD de produção: 63/63 verificações HTTP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e8b53f620
commit
04c8c83e66
29 files changed
+480
-29
No files matched your search
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// ─── Formulários públicos: anti-spam e bloqueio de IP (platform-tools) ──────
|
||||
// Aula experimental, inscrição e eventos usam as defesas partilhadas da frota
|
||||
// em vez de um honeypot local por formulário:
|
||||
// - platform_ip_guard(): um IP banido não chega ao formulário;
|
||||
// - platform_antispam_check(): honeypot, carimbo assinado com tempo mínimo
|
||||
// (time-trap), prova de JavaScript, limite por IP e pontuação de conteúdo.
|
||||
// Uma submissão recusada recebe a mesma resposta de sucesso (o bot não aprende
|
||||
// nada) e fica em `blocked_submissions`, para um falso positivo se poder ler.
|
||||
//
|
||||
// Falha aberto: se o módulo rebentar, o formulário continua a funcionar —
|
||||
// segurança que derruba o formulário é uma avaria, não uma proteção.
|
||||
|
||||
require_once __DIR__ . '/../shared/platform-tools/functions_ip_ban.php';
|
||||
require_once __DIR__ . '/../shared/platform-tools/functions_antispam_forms.php';
|
||||
|
||||
platform_antispam_config([
|
||||
// NÃO mudar num site a correr: invalida os formulários abertos nesse momento.
|
||||
'key_domain' => 'fitme-antispam|',
|
||||
'log_table' => 'blocked_submissions',
|
||||
'keywords' => ['seo', 'backlink', 'backlinks', 'crypto', 'bitcoin', 'casino', 'viagra', 'loan',
|
||||
'guest post', 'web design', 'website traffic', 'ranking', 'forex', 'investment opportunity'],
|
||||
// Marcas do português: quem as usa não é pontuado como «texto estrangeiro».
|
||||
'native' => '/\b(ol[aá]|bom dia|boa (tarde|noite)|gostaria|queria|aulas?|gin[aá]sio|treino|obrigad[oa]|marcar|experimental|hor[aá]rio)\b/u',
|
||||
]);
|
||||
|
||||
// Devolve o motivo da recusa (já registado) ou null para seguir.
|
||||
function public_form_screen(PDO $pdo, string $form, string $table, string $name, string $text): ?string {
|
||||
try {
|
||||
platform_ip_guard($pdo); // sai com 403 se o IP estiver banido
|
||||
return platform_antispam_check($pdo, $form, $table, ['name' => $name, 'text' => $text]);
|
||||
} catch (Throwable $e) {
|
||||
error_log('[antispam] ' . $form . ': ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Os campos escondidos que o formulário tem de levar (honeypot + carimbo +
|
||||
// prova de JS). Sem eles o carimbo falha e a submissão é recusada.
|
||||
function public_form_trap(string $form): string {
|
||||
try {
|
||||
return platform_antispam_trap_field($form, $GLOBALS['pdo'] ?? null);
|
||||
} catch (Throwable $e) {
|
||||
error_log('[antispam] trap ' . $form . ': ' . $e->getMessage());
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user