PHPackages                             tmi/anti-spam - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. tmi/anti-spam

ActiveSymfony-bundle[Validation &amp; Sanitization](/categories/validation)

tmi/anti-spam
=============

Framework-light, presentation-free anti-spam primitives for Symfony forms: honeypot + timestamp + JS-token detection and a reusable form-type extension.

v1.0.0(1mo ago)010MITPHPPHP &gt;=8.4CI passing

Since Jun 3Pushed 1mo agoCompare

[ Source](https://github.com/CreativeNative/anti-spam)[ Packagist](https://packagist.org/packages/tmi/anti-spam)[ Docs](https://github.com/CreativeNative/anti-spam)[ RSS](/packages/tmi-anti-spam/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (2)Used By (0)

tmi/anti-spam
=============

[](#tmianti-spam)

Framework-light, presentation-free anti-spam primitives for Symfony forms.

**Layer 1 — honeypot stack** (free, no CAPTCHA, no third party). Three cheap, JS-and-bot-resistant signals:

- **Honeypot** — a hidden `website` field a human never fills.
- **Timestamp** — `_loaded_at` (unix seconds, set by JS on page load). Submissions faster than 3 s or older than 6 h are rejected.
- **JS token** — `_js_token`, set by JS on first user interaction to the form's expected constant. A missing/mismatched token means JS never ran (bot).

**Layer 2 — Cloudflare Turnstile** (optional, stronger). A decoupled `siteverify`wrapper with an injected hostname allow-list — catches what the honeypot can't and vice versa. Use both for defence-in-depth.

Carries **no** entities, templates, translations or routes — pure logic + one form-type extension + one Stimulus controller. Detachable by design.

Install
-------

[](#install)

```
composer require tmi/anti-spam
```

Register the bundle (Symfony Flex does this automatically):

```
// config/bundles.php
return [
    // ...
    Tmi\AntiSpam\TmiAntiSpamBundle::class => ['all' => true],
];
```

Usage
-----

[](#usage)

### 1. Add the honeypot fields to a form

[](#1-add-the-honeypot-fields-to-a-form)

```
public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'data_class' => MyRequest::class,
        'honeypot'   => true, // injects website / _loaded_at / _js_token (mapped:false)
    ]);
}
```

### 2. Wire the JS (Stimulus)

[](#2-wire-the-js-stimulus)

```

```

Copy `assets/controllers/antispam_controller.js` into your app's `assets/controllers/` (or register the package's UX assets).

### 3. Check on submit

[](#3-check-on-submit)

```
use Tmi\AntiSpam\HoneypotFields;
use Tmi\AntiSpam\Service\SpamGuard;

$reason = $spamGuard->detect(
    (string) $form->get(HoneypotFields::WEBSITE)->getData(),
    (string) $form->get(HoneypotFields::LOADED_AT)->getData(),
    (string) $form->get(HoneypotFields::JS_TOKEN)->getData(),
    MyType::JS_TOKEN,
);

if (null !== $reason) {
    // silently drop — no flash, no persistence
}
```

Pair it with a Symfony `rate_limiter` on the submit endpoint for layered defence.

### 4. (Optional) Cloudflare Turnstile

[](#4-optional-cloudflare-turnstile)

`TurnstileVerifier` is app-decoupled — it takes the allowed hostnames as a constructor argument rather than reading any app host registry, so subclass it (or wire it) to supply your own list. The HTTP client should be a scoped client pointed at `https://challenges.cloudflare.com`; the secret stays server-side.

```
use Tmi\AntiSpam\Service\TurnstileVerifier;

final class AppTurnstileVerifier extends TurnstileVerifier
{
    public function __construct(HttpClientInterface $turnstileClient, string $secret, LoggerInterface $logger)
    {
        parent::__construct($turnstileClient, $secret, $logger, ['example.com', 'www.example.com']);
    }
}

// in the controller, BEFORE the honeypot check:
$reason = $verifier->verify(
    $request->request->getString('cf-turnstile-response'),
    $request->getClientIp() ?? '',
    'newsletter', // the action your widget declared
);
// null = ok; otherwise 'missing-token'|'invalid-token'|'timeout-or-duplicate'|'hostname-mismatch'|'action-mismatch'|'network-error'
```

Hostnames are normalized (lowercase + trailing `.local` strip for dev parity) before comparison. The widget JS + sitekey stay in your app.

License
-------

[](#license)

MIT.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

51d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/5bb90de3396a5ac32cfb88f38025a875432b70b00228bb9f652280614968af3b?d=identicon)[CreativeNative](/maintainers/CreativeNative)

---

Tags

symfonyspamformHoneypotanti-spam

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/tmi-anti-spam/health.svg)

```
[![Health](https://phpackages.com/badges/tmi-anti-spam/health.svg)](https://phpackages.com/packages/tmi-anti-spam)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M400](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)[contao/core-bundle

Contao Open Source CMS

1231.6M2.8k](/packages/contao-core-bundle)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M600](/packages/shopware-core)[oro/platform

Business Application Platform (BAP)

645143.5k116](/packages/oro-platform)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M215](/packages/sulu-sulu)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
