Replace v1 with v2 codebase
Full rewrite: swap out the v1 framework (src/, controllers/, views/, twig/, sass/, skeleton/) for the working v2 codebase from phpproject (App/, novaconium/, public/).
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Lib;
|
||||
|
||||
/**
|
||||
* Self-hosted spam detection for any form sidecar: a honeypot field plus
|
||||
* a submission-timing check. No external CAPTCHA service, no CDN script,
|
||||
* no site key/secret key, no outbound API call — see /admin/docs/sidecars's
|
||||
* "Spam prevention" section for the full write-up and App/pages/contact/
|
||||
* for a working example.
|
||||
*
|
||||
* Pair this with a hidden honeypot input (named per $honeypotField below,
|
||||
* hidden off-screen via the .hp-field CSS class — not display:none, since
|
||||
* some bots specifically skip fields hidden that way) and a hidden
|
||||
* `renderedAt()`-valued timestamp field in the form's Twig template.
|
||||
*/
|
||||
final class SpamGuard
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $honeypotField = 'website',
|
||||
private readonly string $timestampField = 'rendered_at',
|
||||
private readonly int $minSeconds = 2,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when rendering the form (i.e. in the sidecar's return
|
||||
* array, GET or POST) and put the result in a hidden field named
|
||||
* $timestampField for isSpam() to read back on submit.
|
||||
*/
|
||||
public function renderedAt(): int
|
||||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $post typically $_POST
|
||||
*/
|
||||
public function isSpam(array $post): bool
|
||||
{
|
||||
$honeypotFilled = trim((string) ($post[$this->honeypotField] ?? '')) !== '';
|
||||
|
||||
$renderedAt = (int) ($post[$this->timestampField] ?? 0);
|
||||
// Not cryptographically signed, so a determined bot could forge
|
||||
// this — it's a deterrent against unsophisticated spam, not a
|
||||
// security boundary.
|
||||
$tooFast = $renderedAt === 0 || (time() - $renderedAt) < $this->minSeconds;
|
||||
|
||||
return $honeypotFilled || $tooFast;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user