How to Add BotDetect PHP CAPTCHA Protection to Symfony 4 Applications

Adding BotDetect PHP Captcha protection to your Symfony MVC applications requires a slightly different approach than adding it to basic PHP websites, but is still straightforward. This page will guide you through the necessary steps and explain the available options.

First Time Here?

Check the BotDetect Symfony 4 Captcha Quickstart for key integration steps.

Prerequisites

Table of Contents

The BotDetect Symfony CAPTCHA Integration Package

Symfony is a MVC framework that leverages certain conventions to provide a rich set of functionality to PHP application developers. Therefore adding BotDetect Captcha into Symfony based site or application requires a layer of integration code to conform to those conventions. This enables BotDetect Captcha to integrate seamlessly and be used according to expectations of Symfony developers.

Path Aliases Used Throughout This Guide

For convenience purposes we are providing the BotDetect Captcha Symfony integration code packaged as a Symfony composer package.

You can get the whole BotDetect Symfony Captcha integration package here. The package contains the integration code, basic Captcha validation example, an contact form validation example. There is also an example of adding BotDetect Captcha into FOSUserBundle Login and Register forms.

The BotDetect Symfony CaptchaBundle

BotDetect Symfony CaptchaBundle is available at https://packagist.org/packages/captcha-com/symfony-captcha-bundle

The CaptchaBundle includes a wrapper class around the regular BotDetect Captcha Library for use in your application.

The CaptchaBundle also includes separate Controller that handles Captcha image, sound, and resources requests, which use
http://<MY_SYMFONY_WEBROOT>/captcha-handler Urls by default.

Symfony Basic BotDetect CAPTCHA Example

This basic Symfony 4 Captcha example shows how to use the CaptchaBundle in your form, and validate user input through the ValidCaptcha constraint in your entity.

  • Config: config/packages/captcha.php
  • Form Type: src/Form/Type/ExampleType.php
  • Entity: src/Entity/Example.php
  • Controller: src/Controllers/ExampleController.php
  • View: templates/example/index.html.twig

Form Validation BotDetect Symfony CAPTCHA Example

This Symfony 4 form validation Captcha example shows how to use the CaptchaBundle in form and validate user input through the ValidCaptcha constraint in your entity by implementing a simple contact form.

  • Config: config/packages/captcha.php
  • Form Type: src/Form/Type/ContactType.php
  • Entity: src/Entity/Contact.php
  • Controller: src/Controllers/ContactController.php
  • View: src/templates/contact/index.html.twig

Provided examples are available inside of a single Symfony app via their respective controllers:

http://<MY_SYMFONY_WEBROOT>/example
http://<MY_SYMFONY_WEBROOT>/contact

You can copy the whole preconfigured Symfony app from the BotDetect Captcha Symfony Package somewhere on your development web server and examine it there.

1. Include BotDetect CAPTCHA in Your Symfony MVC Application

Install the BotDetect Symfony CaptchaBundle

Note: If you do not have Composer yet, you can install it by following the instructions on https://getcomposer.org

If you have Git installed on your development machine, you should use the following installation procedure:

Step 1: Download CaptchaBundle using composer

Run the following command in your application's root directory:

Step 2: Import CaptchaBundle routing file (config/routes.yml):

captcha_routing:
  resource: "@CaptchaBundle/Resources/config/routing.yml"

A Note On PHP Session Persistence

The CaptchaBundle requires persistent per-user server storage to work properly. By default, it uses Symfony Session, which is convenient in most use cases.

If your environment requires a different approach to handle Session data, you can be easily looking for the documentation on symfony site. For example, in case, you want to store Sessions in the Database, then you can follow this cookbook entry to use PDOSessionHandler.

Note that a Session cleanup right after creating a Captcha class instance may cause an error since BotDetect will not find its Session data.

2. Display BotDetect CAPTCHA in Your Symfony Form

Captcha configuration options

<?php if (!class_exists('CaptchaConfiguration')) { return; }

// BotDetect PHP Captcha configuration options

return [
  // Captcha configuration for example page
  'ExampleCaptcha' => [
    'UserInputID' => 'captchaCode',
    'ImageWidth' => 250,
    'ImageHeight' => 50,
  ],

];

In order to use the CaptchaBundle, you must declare Captcha configuration in config/packages/captcha.php file following the structure given above. The ExampleCaptcha is an example name and will be used as captcha field type, or to get a captcha object instance in some scenarios that you do not want to use captcha field type to display captcha in your form. You should pick a name that best matches your usage scenario like: LoginCaptcha, ContactCaptcha, etc. You can find a full list of available Captcha configuration options and related instructions at the Captcha configuration options page.

In case you need different Captcha for another form in your application, here is the example how to add additional captcha configuration for a login form:

<?php if (!class_exists('CaptchaConfiguration')) { return; }

// BotDetect PHP Captcha configuration options

return [
  // Captcha configuration for example page
  'ExampleCaptcha' => [
    'UserInputID' => 'captchaCode',
    'ImageWidth' => 250,
    'ImageHeight' => 50,
  ],

  // Captcha configuration for login page
  'LoginCaptcha' => [
    'UserInputID' => 'captchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 6),
    'ImageStyle' => [
      ImageStyle::Radar,
      ImageStyle::Collage,
      ImageStyle::Fingerprints,
    ],
  ],

];

Compose Your Symfony Form With BotDetect CAPTCHA Display

namespace App\Form\Type;

use Captcha\Bundle\CaptchaBundle\Form\Type\CaptchaType;

class ExampleType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder->add('captchaCode', CaptchaType::class, array(
      'captchaConfig' => 'ExampleCaptcha'
    ));
  }

CaptchaBundle provides CaptchaType to add Captcha in your forms. It is required to declare captchaConfig option and assign it a captcha configuration key defined in config/packages/captcha.php file.

3. Validate CAPTCHA In Your Symfony Entity

Validate the Submitted CAPTCHA Code User Input

namespace App\Entity;

use Captcha\Bundle\CaptchaBundle\Validator\Constraints as CaptchaAssert;

class Example
{
  /**
   * @CaptchaAssert\ValidCaptcha(
   *      message = "CAPTCHA validation failed, try again."
   * )
   */
  protected $captchaCode;

  public function getCaptchaCode()
  {
    return $this->captchaCode;
  }

  public function setCaptchaCode($captchaCode)
  {
    $this->captchaCode = $captchaCode;
  }
}

After Captcha is displayed in your form, you would want to validate the Captcha code user submitted. To do that, you should simply use the ValidCaptcha constraint in your entity that is available in the CaptchaBundle. You can also customize an error message by adding your custom error message to message option.

Handle CAPTCHA Validation Failure / Success

Symfony validation will abort further processing and display an error on failure, or proceed with a protected form action on success:

$form ->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
  // TODO: Captcha validation passed:
  // continue with form processing, knowing the submission was made by a human
}

This ensures particular sensitive action to be executed only if a human filled the form.