Add captch in Drupal 8 Custom form using Securimage"

This is an easy guide to help you implement captcha to your Drupal 8 custom form using securimage

Install lib through composer:

1
 composer require dapphp/securimage

We set up this method in a controller class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Returns the captcha image
public function getCaptcha(){

 // Generate the captcha session
 $temp_store = \Drupal::service('user.private_tempstore')->get('my_module_name');
 $session_id = sha1(uniqid($_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT']));
 $temp_store->set('captcha_id', $session_id);

 // Configure the captcha
 $captcha_options = [
 'captchaId' => $session_id,
 'image_width' => 240,
 'image_height' => 70,
 'no_exit' => true,
 'use_database' => false,
 'send_headers' => false,
 'send_headers' => false,
 ];


 // Return the captcha image
 $captcha = new \Securimage($captcha_options);
 $response = new Response();
 $response->headers->set('Content-Type', 'image/png');
 $response->headers->set('Content-Disposition', 'inline');
 $response->setContent($captcha->show());

 return $response;
}

Create a route to hit generate image:

1
2
3
4
5
6
my_module_name.captchaimage:
 path: /getcaptcha
  defaults:
 _controller: Drupal\my_module_name\Controller\MyController::getCaptcha
  requirements:
 _permission: 'access content'

on the Form build method render the image like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Add the captcha
$getBase = \Drupal::request()->getSchemeAndHttpHost();
$form['captcha'] = [
 '#type' => 'html_tag',
 '#tag' => 'img',
 '#prefix' => '<div class="row"><div class="col-md-4">',
 '#suffix' => '</div></div>',
 '#attributes' => [
 'id' => ['captcha'],
 'class' => ['my_captcha'],
 'src' => $getBase . '/getcaptcha', ],
];

$form['captcha_input'] = [
 '#type' => 'textfield',
 '#prefix' => '<div class="row"><div class="col-md-4">',
 '#suffix' => '</div></div>',
 '#attributes' => [
 'class' => ['captcha-text'],
 ],
];
$form['text']['#markup'] = "<a href='#' id='captcha_refresh'>Refresh</a>";

On the validate method you validate the form captcha as follow:

1
2
3
4
5
6
7
// Validate the captcha
$captcha = new \Securimage();
if (!$captcha->check($form_state->getValue("captcha_input"))) {
 $form_state->setErrorByName('captcha_input', t("Wrong captcha"));
return false;

}

Handle the refresh button with javascript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Captcha refresh

var captcha = document.getElementById("captcha");

if(captcha){
    jQuery("#captcha_refresh").click(function(e){
        d = new Date();
        captcha.setAttribute("src", siteBase + "/getcaptcha?" + d.getTime());
        e.preventDefault();
    });

}