Symfony2 Form Validation BotDetect CAPTCHA Example

First Time Here?

Check the BotDetect Symfony2 Captcha Quickstart for key integration steps.

Symfony Form Validation BotDetect CAPTCHA Example shows how to integrate CaptchaBundle in a form. We have also demonstrated how to create the ValidCaptcha constraint in order to validate captcha code user submits.

The brief example is based around a contact form which sends email if user input is considered valid -– a likely real world scenario for Captcha protection integration.

Files for this ('bd-captcha-symfony2-examples') example are:

All files are available for download as a part of the BotDetect Captcha Symfony integration package.

Symfony2 Contact BotDetect Captcha validation screenshot

Config - /app/config/captcha.php

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

// BotDetect PHP Captcha configuration options

return [
  // Captcha configuration for contact page
  'ContactCaptcha' => [
    'UserInputID' => 'captchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 6),
    'ImageStyle' => ImageStyle::AncientMosaic,
  ],

];

In order to use the CaptchaBundle, we have defined Captcha configuration which will be used as a captcha field type in ContactType form. Detailed description of this approach is available in a BotDetect Symfony2 integration guide.

Type - /src/AppBundle/Form/Type/ContactType.php

<?php namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class ContactType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder
      ->add('name', 'text')
      ->add('email', 'email')
      ->add('subject', 'text')
      ->add('message', 'textarea')
      ->add('captchaCode', 'captcha', array(
        'captchaConfig' => 'captcha.config.contact_captcha',
        'label' => 'Retype the characters from the picture'
      ))
      ->add('submit', 'submit')
    ;
  }

  public function getName()
  {
    return 'contact';
  }
}

The above code uses the captcha field type to add Captcha to contact form. It is required to declare captchaConfig option and assign it a captcha configuration variable defined in config.yml file.

Entity - /src/AppBundle/Entity/Contact.php

<?php namespace AppBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;
use Captcha\Bundle\CaptchaBundle\Validator\Constraints as CaptchaAssert;

class Contact
{
  /**
   * @Assert\Length(
   *      min = 2,
   *      max = 10,
   *      minMessage = "Your name must be at least {{ limit }} characters long",
   *      maxMessage = "Your name cannot be longer than {{ limit }} characters"
   * )
   */
  protected $name;

  /**
   * @Assert\Email(
   *      message = "The email '{{ value }}' is not a valid email.",
   * )
   */
  protected $email;

  /**
   * @Assert\Length(
   *      min = 1,
   *      max = 50,
   *      minMessage = "Your subject must be at least {{ limit }} characters long",
   *      maxMessage = "Your subject cannot be longer than {{ limit }} characters"
   * )
   */
  protected $subject;

  /**
   * @Assert\Length(
   *      min = 2,
   *      max = 255,
   *      minMessage = "Your message must be at least {{ limit }} characters long",
   *      maxMessage = "Your message cannot be longer than {{ limit }} characters"
   * )
   */
  protected $message;

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

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

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

  public function getName()
  {
    return $this->name;
  }

  public function setName($name)
  {
    $this->name = $name;
  }

  public function getEmail()
  {
    return $this->email;
  }

  public function setEmail($email)
  {
    $this->email = $email;
  }

  public function getSubject()
  {
    return $this->subject;
  }

  public function setSubject($subject)
  {
    $this->subject = $subject;
  }

  public function getMessage()
  {
    return $this->message;
  }

  public function setMessage($message)
  {
    $this->message = $message;
  }
}

To validate the captchaCode field in contact form, we have added the ValidCaptcha constraint to Contact Entity.

Controller - /src/AppBundle/Controllers/ContactController.php

<?php namespace AppBundle\Controller;

use AppBundle\Entity\Contact;
use AppBundle\Form\Type\ContactType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class ContactController extends Controller
{
  /**
   * @Route("/contact")
   */
  public function getForm(Request $request)
  {
    // create contact form
    $contactForm = $this->createForm(new ContactType(), new Contact());

    // initially, the message shown to the visitor is empty
    $message = '';

    $contactForm ->handleRequest($request);
    if ($contactForm->isValid()) {
      // Captcha validation passed
      // TODO: send email
      $message = 'Your message was sent successfully.';
    }

    return $this->render('AppBundle:Contact:contact.html.twig', array(
      'form' => $contactForm->createView(),
      'message' => $message
    ));
  }
}

When user submits a valid captcha code, isValid() returns true. Before redirecting user, it is possible to perform some actions using the $contactForm object. Code above assigns a success message to the $message variable which will be displayed on a contact page.

View - /src/AppBundle/Resources/views/Contact/contact.html.twig

<!DOCTYPE html>
<html>
<head>
  <title>Symfony2 Form Validation BotDetect CAPTCHA Example</title>
</head>

<body>
  <h2>Symfony2 Form Validation BotDetect CAPTCHA Example</h2>
  
  {# show message #}
  {% if message is not empty %}
    <p>{{ message }}</p>
  {% endif %}
  
  {{ form_start(form) }}
  {{ form_widget(form) }}
  {{ form_end(form) }}
</body>
</html>

The form has already been created, the next step is render it by using a set of forms helper functions, and to prints out a message (set in Controller) about Captcha validation success.