Markus Michalski FAQ

ALTCHA Spam Protection: Extending

Extension points of the ALTCHA Spam Protection module for OXID 7: checking your own forms through SpamProtectionFacade, using the widget in your own templates, rejection reasons and error message keys.

Deutsche Version

Back to overview

ALTCHA Spam Protection: Extending

Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net

On its own the module protects only contact, newsletter and registration. You can use the same check chain for your own forms. The classes are not a documented public API with stability guarantees; they live in the namespace Mmd\AltchaIntegration and are described here as they appear in the code.

Checking your own form on the server

The service SpamProtectionFacade is registered as public in the container and runs the whole check chain. A custom controller extension calls it before the actual processing:

use Mmd\AltchaIntegration\Service\SpamProtectionFacade;
use Mmd\AltchaIntegration\Struct\SpamCheckRequest;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;

$facade = ContainerFactory::getInstance()
    ->getContainer()
    ->get(SpamProtectionFacade::class);

$request = Registry::getRequest();

$result = $facade->validate(new SpamCheckRequest(
    action: 'my_form',
    ipAddress: $clientIp,
    altchaPayload: (string) $request->getRequestParameter('altcha'),
    honeypotValue: (string) $request->getRequestParameter($facade->getHoneypotFieldName()),
    formData: [
        'email' => $email,
        'firstName' => $firstName,
        'lastName' => $lastName,
    ],
));

if (!$result->isValid()) {
    // evaluate $result->reason and $result->retryAfterSeconds
}
Field of SpamCheckRequest Meaning
action Name of the form, at most 50 characters. The rate limit counts per action and client separately
ipAddress Client address. The module's own extensions take it from X-Forwarded-For (first entry) or REMOTE_ADDR
altchaPayload Content of the POST field altcha
honeypotValue Content of the honeypot field
formData Optional. Only email, firstName, lastName and billingAddress with street and city are evaluated. If the array is empty, content validation is skipped

If spam protection is switched off as a whole, validate() always returns a valid result.

Rejection reasons

$result->reason holds one of these values:

Reason Cause Message key in the bundled controllers
honeypot_triggered Honeypot field not empty MMD_ALTCHA_ERROR_SPAM_DETECTED
content_validation_failed At least two fields flagged MMD_ALTCHA_ERROR_CONTENT_VALIDATION
altcha_missing Field altcha empty MMD_ALTCHA_ERROR_VERIFICATION_FAILED
altcha_invalid Solution not readable as Base64 or JSON, a required field is missing, the algorithm is not SHA-256, or signature or hash do not match MMD_ALTCHA_ERROR_VERIFICATION_FAILED
altcha_expired Challenge too old MMD_ALTCHA_ERROR_GENERIC
altcha_replay Challenge already used MMD_ALTCHA_ERROR_GENERIC
rate_limit_exceeded Too many requests, retryAfterSeconds is set MMD_ALTCHA_ERROR_RATE_LIMITED, followed by MMD_ALTCHA_RETRY_AFTER

The translations of the keys are in translations/de/mmd_altcha_lang.php and translations/en/mmd_altcha_lang.php. The keys MMD_ALTCHA_ERROR_CHALLENGE_EXPIRED and MMD_ALTCHA_ERROR_CHALLENGE_REUSED are defined there, but the bundled controllers do not use them.

Widget in your own templates

The widget can be included in any Twig template. Example and prerequisites are on the Storefront page. The widget adds the POST field altcha to the surrounding form by itself.

Extended OXID classes

An overview of the extended core classes is on the Technical page. If your shop extends the same classes as well, the module order in the admin decides which extension runs first.