Skip to main content

Math CAPTCHA

This guide explains how to add a custom math-based CAPTCHA to your form using the Email Manager plugin for Kirby. The CAPTCHA enhances security by requiring users to solve a simple math problem, ensuring that submissions come from real people.

CAPTCHAs help prevent spam by verifying that a human is interacting with your form. In this guide, you’ll create a math-based CAPTCHA that dynamically generates a math problem, validates the user’s response, and ensures clean session management after validation.

By the end of this guide, your form will include a robust CAPTCHA system tailored to your needs.

A personal note: I have two forms on my personal website without any CAPTCHA. In the first year, I only received two spam emails, both probably written by humans.

Configure the Blueprint

To integrate the CAPTCHA, start by adding the necessary configuration to your blueprint file. This file defines how the CAPTCHA behaves, including its frontend rendering and error messages.

Here’s how your configuration should look:

captcha:
  frontend:
    snippet: captcha/math  # Path to the CAPTCHA snippet
    fieldname: math-captcha  # Field name used in the form
  errormessages:
    missing:
      en: "Please solve the math problem"
      de: "Bitte lösen Sie die Rechenaufgabe"
    invalid:
      en: "Wrong result, please try again"
      de: "Falsches Ergebnis, bitte versuchen Sie es erneut"

This configuration connects the CAPTCHA logic to the form, ensuring proper integration with the rest of your Email Manager setup.

The snippet specifies the path to the snippet that generates and displays the CAPTCHA.

The field_name identifies the field in the form where users will input their answer.

Meanwhile, the errorsection provides multilingual error messages to handle cases where the CAPTCHA response is missing or incorrect.

Create the snippet

Next, create the CAPTCHA snippet at site/snippets/captcha/math.php. This snippet is responsible for generating the math problem and storing the correct answer in the session.

In the snippet, two random numbers are generated to form a simple addition problem. The correct answer is calculated and saved in the session to ensure it can be validated later.

The snippet also dynamically renders the math problem in the form, along with a user input field for the answer.

<?php
use KirbyEmailManager\Helpers\FormHelper;

// Generate two random numbers between 1 and 10
$num1 = rand(1, 10);
$num2 = rand(1, 10);

// Calculate the result and store it in the session
$session = kirby()->session();
$session->set('math_captcha_result', $num1 + $num2);

$fieldName = $fieldName ?? 'math-captcha';
?>

<div class="<?= FormHelper::getClassName('field', $config) ?>">
    <label for="<?= $fieldName ?>" class="<?= FormHelper::getClassName('label', $config) ?>">
        <?= $num1 ?> + <?= $num2 ?> = ?
    </label>
    
    <input type="number" 
           id="<?= $fieldName ?>" 
           name="<?= $fieldName ?>" 
           class="<?= FormHelper::getClassName('input', $config) ?>"
           required>

    <?php if (isset($error)): ?>
        <p class="<?= FormHelper::getClassName('error', $config) ?>">
            <?= $error ?>
        </p>
    <?php endif ?>
</div>

The dynamic behavior of the snippet ensures that each user receives a unique math problem while maintaining a clean and organized form layout.

Add the Validation Callback

Finally, implement the validation logic in your Kirby configuration file (site/config/config.php). The validation callback checks the user’s input against the correct answer stored in the session.

The session ensures that the answer is securely stored and cannot be tampered with. If the user’s response matches the stored answer, the validation passes, and the form can be submitted. If the response is incorrect or missing, an appropriate error message is displayed. After validation, the session is cleared to prevent reuse or conflicts in future form submissions.

Here’s an example of the validation callback:

'philippoehrlein.kirby-email-manager' => [
    'captcha' => [
        'callback' => function($response, $config) {
            $session = kirby()->session();
            $expected = $session->get('math_captcha_result');
            
            // Check if the answer is correct
            $isValid = $expected !== null && 
                        $response !== null && 
                        (int)$response === $expected;
            
            // Delete the session value after validation
            $session->remove('math_captcha_result');
            
            return $isValid;
        }
    ]
]

This implementation ensures that your CAPTCHA is both effective and secure, providing a seamless experience for users while keeping bots at bay.

Summary

By following these steps, you’ve added a custom math CAPTCHA to your Kirby form. During form submission, users solve a dynamically generated math problem, and their input is validated against the session-stored answer. This approach ensures robust security while keeping the user experience simple and intuitive. For further customization, consider adjusting the range of numbers, introducing more complex problems, or refining the error messages to fit your audience’s needs.