CakePHP 3 Auth CAPTCHA Example

This example demonstrates how to integrate BotDetect PHP Captcha into login and register forms in a scenario where CakePHP Auth Component is used to authenticate users to your application.

First Time Here?

Check the BotDetect CakePHP 3 Captcha Quickstart for key integration steps.

When CakePHP Auth Component is turned on in your application, it requires you to use database. Here is how to create it:

First, we need to configure database connection with entering connection details into the <MY_CAKE_WEBROOT>/config/app.php file.

Next, we need to create users table -- using Migrations. We have prepared a create_users migration which is located at: <MY_CAKE_WEBROOT>/config/Migrations/

To create users table, run the following command in your application's root directory:

Files for this example are:

The files are available for download as a part of the BotDetect Captcha CakePHP integration package.

Config – /config/captcha.php

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

// BotDetect PHP Captcha configuration options 

return [ 
  // Captcha configuration for login page 
  'LoginCaptcha' => [ 
    'UserInputID' => 'CaptchaCode', 
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 6), 
    'ImageStyle' => [ 
      ImageStyle::Radar, 
      ImageStyle::Collage, 
      ImageStyle::Fingerprints, 
    ], 
  ], 
  
  // Captcha configuration for register page 
  'RegisterCaptcha' => [ 
    'UserInputID' => 'CaptchaCode', 
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 7), 
    'CodeStyle' => CodeStyle::Alpha, 
    'CustomLightColor' => '#9966FF', 
  ], 
  
]; 

In order to use the CakePHP CAPTCHA Plugin, we have declared Captcha configuration which will be used when loading Captcha component in login and register methods of UsersController. Detailed description of this approach is available in a BotDetect CakePHP 3 integration guide.

View – /src/Template/Users/login.ctp

<!-- include the BotDetect layout stylesheet --> 
<?= $this->Html->css(captcha_layout_stylesheet_url(), ['inline' => false]) ?> 
 
<div class="users form"> 
<?= $this->Flash->render('auth') ?> 
<?= $this->Form->create() ?> 
  <fieldset> 
    <legend><?= __('Please enter your username and password') ?></legend> 
    <?= $this->Form->input('username') ?> 
    <?= $this->Form->input('password') ?> 

    <!-- show captcha image html --> 
    <?= captcha_image_html() ?> 

    <!-- Captcha code user input textbox --> 
    <?= $this->Form->input('CaptchaCode', [ 
      'label' => 'Retype the characters from the picture:', 
      'maxlength' => '10', 
      'id' => 'CaptchaCode' 
    ]) ?> 
  </fieldset> 


<?= $this->Form->button(__('Login'), ['style' => 'float: left; margin-left: 20px;']) ?> 
<?= $this->Form->end() ?> 
</div> 

The above code is used to create CakePHP FormHelper. To display authentication in a view, we output the captcha_image_html() helper function.

Also we have added Captcha Code input field to view. This Captcha Code input will be checked in the login() method later.

To display correctly, BotDetect Captcha PHP requires you to include its CSS. We have used HtmlHelper::css() to create a link to the CSS file.

View – /src/Template/Users/register.ctp

<!-- include the BotDetect layout stylesheet --> 
<?= $this->Html->css(captcha_layout_stylesheet_url(), ['inline' => false]) ?> 
 
<div class="users form"> 
<?= $this->Form->create($user) ?> 
  <fieldset> 
    <legend><?= __('Register User') ?></legend> 
    <?= $this->Form->input('username') ?> 
    <?= $this->Form->input('email') ?> 
    <?= $this->Form->input('password') ?> 
    <?= $this->Form->input('confirm_password', ['type' => 'password']) ?> 

    <!-- show captcha image html --> 
    <?= captcha_image_html() ?> 

    <!-- Captcha code user input textbox --> 
    <?= $this->Form->input('CaptchaCode', [ 
      'label' => 'Retype the characters from the picture:', 
      'maxlength' => '10', 
      'id' => 'CaptchaCode' 
    ]) ?> 
   </fieldset> 
<?= $this->Form->button(__('Register'), ['style' => 'float: left; margin-left: 20px;']) ?> 
<?= $this->Form->end() ?> 
</div> 

The above code is used to create CakePHP FormHelper. To display authentication in a view, we output the captcha_image_html() helper function.

Also we have added Captcha Code input field to view. This Capthca Code input will be checked in the register() method later.

To display correctly, BotDetect Captcha PHP requires you to include its CSS. We have used HtmlHelper::css() to create a link to the CSS file.

Controller – /src/Controller/UsersController.php

<?php namespace App\Controller; 

use App\Controller\AppController; 
use Cake\Event\Event; 

class UsersController extends AppController 
{ 
  public function beforeFilter(Event $event) 
  { 
    parent::beforeFilter($event); 

    $this->viewBuilder()->layout('auth'); 

    // Allow users to register and logout. 
    $this->Auth->allow(['register', 'logout']); 
  } 

  public function login() 
  { 
    // load the Captcha component and set its parameter 
    $this->loadComponent('CakeCaptcha.Captcha', [ 
      'captchaConfig' => 'LoginCaptcha' 
    ]); 

    if ($this->request->is('post')) { 

      // validate the user-entered Captcha code 
      $isHuman = captcha_validate($this->request->data['CaptchaCode']); 

      // clear previous user input, since each Captcha code can only be validated once 
      unset($this->request->data['CaptchaCode']); 
      
      if ($isHuman) { 
        $user = $this->Auth->identify(); 
        if ($user) { 
          $this->Auth->setUser($user); 
          return $this->redirect($this->Auth->redirectUrl()); 
        } 
        $this->Flash->error(__('Invalid username or password, try again')); 
      } else { 
        $this->Flash->error(__('CAPTCHA validation failed, try again.')); 
      } 
    } 
  } 

  public function register() 
  { 
    // load the Captcha component and set its parameter 
    $this->loadComponent('CakeCaptcha.Captcha', [ 
      'captchaConfig' => 'RegisterCaptcha' 
    ]); 

    $user = $this->Users->newEntity(); 
    if ($this->request->is('post')) { 

      // validate the user-entered Captcha code 
      $isHuman = captcha_validate($this->request->data['CaptchaCode']); 

      // clear previous user input, since each Captcha code can only be validated once 
      unset($this->request->data['CaptchaCode']); 
 
      if ($isHuman) { 
        $query = $this->Users->findAllByUsernameOrEmail($this->request->data['username'], $this->request->data['email']); 
        if ($query->count() == 0) { 
          $user = $this->Users->patchEntity($user, $this->request->data); 
          if ($this->Users->save($user)) { 
            $this->Flash->success(__('The user has been saved.')); 
            return $this->redirect(['action' => 'register']); 
          } 
          $this->Flash->error(__('Unable to add the user.')); 
        } else { 
          $this->Flash->error(__('This user already exists.')); 
        } 
      } else { 
        $this->Flash->error(__('CAPTCHA validation failed, try again.')); 
      } 
        
    } 
    $this->set('user', $user); 
  } 

  public function logout() 
  { 
    return $this->redirect($this->Auth->logout()); 
  } 

  public function index() {} 
} 

The example Controller follows the basic instructions from the BotDetect CakePHP 3 integration guide.

Method: login()

We load the Captcha component at the top of login() method and assign a captcha configuration key to the captchaConfig option that defined in config/captcha.php file (i.e. LoginCaptcha).

The example form submits data to the same Controller action that shows it (login). This is where we check the submitted captcha code and pass it to the captcha_validate helper function.

Method: register()

We load the Captcha component at the top of register() method and assign a captcha configuration key to the captchaConfig option that defined in config/captcha.php file (i.e. RegisterCaptcha).

The example form submits data to the same Controller action that shows it (register). This is where we check the submitted captcha code and pass it to the captcha_validate helper function.