ALTCHA: Installation and Operations
ALTCHA spam protection for Sylius - installation via Composer (Packeton), update, cron jobs for purge and disposable-domain list, uninstall in the correct order
ALTCHA: Installation and Operations
Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net
Installation
Private repository, distributed through Packeton (
https://packeton.markus-michalski.net). Access credentials are provided after license purchase/approval.
{ "repositories": [{ "type": "composer", "url": "https://packeton.markus-michalski.net" }] }
composer require mmd/sylius-altcha-plugin
-
Register the bundle in
config/bundles.php:Mmd\SyliusAltchaPlugin\MmdSyliusAltchaPlugin::class => ['all' => true], -
Import the routes, for example in
config/routes/mmd_sylius_altcha.yaml:mmd_sylius_altcha_admin: resource: "@MmdSyliusAltchaPlugin/config/routes/admin.yaml" mmd_sylius_altcha_shop: resource: "@MmdSyliusAltchaPlugin/config/routes/shop.yaml" -
Run the setup command and publish the widget assets:
bin/console mmd:altcha:setup bin/console assets:installmmd:altcha:setupruns only this plugin's own migrations, never those of your app or other plugins, and is idempotent: running it again after acomposer updatedoes nothing when there is no new migration. It stops and tells you to rundoctrine:migrations:migratefirst if Sylius' own migrations are still open, and it checks that the routes from step 2 are imported, printing the snippet if not (it never writes intoconfig/itself). Plaindoctrine:migrations:migratestill works as a fallback. Run it as the same user as your other console commands; in scripts add--no-interaction.The widget scripts are always served from
<base path>/bundles/mmdsyliusaltchaplugin/, never through Symfony asset packages or Sylius themes -assets:installis enough,sylius:theme:assets:installis not required, and a CDNbase_urls/version_strategysetting does not apply to them. With a CSP, allow'self'inscript-src. -
Set up the cron jobs (see Cron Jobs): the plugin stores short-lived rows for replay protection and rate limiting that nothing else deletes.
Nothing is protected until you enable a channel in the admin (see Configuration). The storefront hooks and admin grids register themselves automatically; nothing else needs to be imported.
Update
composer update mmd/sylius-altcha-plugin
bin/console mmd:altcha:setup --no-interaction
bin/console cache:clear
Running the setup command again after every update is always safe: without a new migration it does nothing.
Cron Jobs
The plugin stores short-lived rows for replay protection and rate limiting. Nothing but the purge cron job deletes them, so it is part of the basic installation.
| Command | Recommended interval | Description |
|---|---|---|
bin/console mmd:altcha:purge |
daily | Removes expired replay-protection rows (already used challenges), expired rate-limit hits (--rate-limit-retention, default 48h) and gibberish-log entries older than 30 days (--gibberish-log-retention) |
bin/console mmd:altcha:update-disposable-domains |
weekly | Refreshes the disposable-mail snapshot from the upstream list; only needed if that check is enabled. Fails closed - a network error or empty response keeps the previous file in place. |
Example crontab for the user that also runs your other console commands (adjust the path):
# daily at 03:15: delete expired replay, rate-limit and gibberish-log rows
15 3 * * * cd /var/www/shop && bin/console mmd:altcha:purge --no-interaction
# Sundays at 03:30: refresh the disposable-domain list (only with the disposable-mail check enabled)
30 3 * * 0 cd /var/www/shop && bin/console mmd:altcha:update-disposable-domains --no-interaction
--rate-limit-retention=<seconds>must exceed the longest rate-limit window you configure (at most 24 hours), otherwise hits are deleted that still need to be counted.
The setup command (mmd:altcha:setup) is not a cron job - it is a one-off, idempotent install/update step.
Uninstall
Order matters - the migrations are only known to Doctrine while the bundle is still registered:
-
Remove every
mmd_altcha_widget()call andmmd_altcha.widget*hook from your templates, and the cron jobs formmd:altcha:purgeandmmd:altcha:update-disposable-domains. -
With the bundle still registered, roll the seven migrations back, newest first:
bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20261007090000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20261003090000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20261002090000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20261001090000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20260930140000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20260930120000' bin/console doctrine:migrations:execute --down 'Mmd\SyliusAltchaPlugin\Migrations\Version20260930100000' -
Remove the route imports and the bundle entry from
config/bundles.php, thencomposer remove mmd/sylius-altcha-plugin.
Dropping the six
mmd_sylius_altcha_*tables by hand instead of rolling back is possible, but then also delete the matching sevenMmd\SyliusAltchaPlugin\Migrations\...rows fromdoctrine_migration_versionsyourself.