CakePHP 2 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 2 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:

For purpose of this example, we'll use the database file included in a BotDetect Captcha CakePHP integration package.

The database file is located at: /bd-captcha-cakephp-2-examples/database/ cakephp_auth.sql.

The next step is to configure connection to your database by entering connection details in the <MYCAKEAPP>/Config/database.php file.

Files for this example are:

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

Config –/app/Config/captcha.php

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

// BotDetect PHP Captcha configuration options 

return array( 
  // Captcha configuration for login and register page 
  'AuthCaptcha' => array( 
    '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 UsersController. Detailed description of this approach is available in a BotDetect CakePHP 2 integration guide.

View – /app/View/Users/login.ctp

<?php 
  // include the BotDetect layout stylesheet 
  echo $this->Html->css(captcha_layout_stylesheet_url(), array('inline' => false)); 
?> 

<div class="users form"> 
<?php echo $this->Form->create('User'); ?> 
  <fieldset> 
    <legend><?php echo __('Login'); ?></legend> 
  <?php 
    echo $this->Form->input('username'); 
    echo $this->Form->input('password'); 

    // display Captcha markup, wrapped in an extra div for layout purposes 
    echo $this->Html->div('captcha', captcha_image_html(), false); 

    // Captcha code user input textbox 
    echo $this->Form->input('CaptchaCode', array( 
        'label' => 'Retype the characters from the picture:', 
        'maxlength' => '10', 
        'style' => 'width: 300px; text-transform: uppercase;' 
      ) 
    ); 
  ?> 
  </fieldset> 
<?php 
  echo $this->Form->end(__('Submit')); 
  echo 'or ' . $this->Html->link('Register', array('controller' => 'users', 'action' => 'add')); 
?> 
</div> 

<div class="actions"> 
  <h3><?php echo __('The default login is:'); ?></h3> 
  Username: administrator <br> 
  Password: password 
</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 – /app/View/Users/add.ctp

<?php 
  if (!$logged_in) { 
    // include the BotDetect layout stylesheet 
    echo $this->Html->css(captcha_layout_stylesheet_url(), array('inline' => false)); 
  } 
?> 

<div class="users form"> 
<?php echo $this->Form->create('User'); ?> 
  <fieldset> 
    <legend><?php echo __('Register'); ?></legend> 
  <?php 
    echo $this->Form->input('name'); 
    echo $this->Form->input('username'); 
    echo $this->Form->input('password'); 
    echo $this->Form->input('password_confirmation', array('type' => 'password')); 
    echo $this->Form->input('email'); 

    if ($logged_in && $is_admin) { 
      echo $this->Form->input('role', array( 
        'options' => array('admin' => 'Admin', 'author' => 'Author') 
      )); 
    } 

    if (!$logged_in) { 
      // display Captcha markup, wrapped in an extra div for layout purposes 
      echo $this->Html->div('captcha', captcha_image_html(), false); 

      // Captcha code user input textbox 
      echo $this->Form->input('CaptchaCode', array( 
          'label' => 'Retype the characters from the picture:', 
          'maxlength' => '10', 
          'style' => 'width: 300px; text-transform: uppercase;' 
        ) 
      ); 
    } 
  ?> 
  </fieldset> 
<?php echo $this->Form->end(__('Submit')); ?> 
</div> 
<div class="actions"> 
  <h3><?php echo __('Actions'); ?></h3> 
  <ul> 

    <li><?php echo $this->Html->link(__('List Users'), array('action' => 'index')); ?></li> 
  </ul> 
</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 add() 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 – /app/Controller/UsersController.php

<?php 
App::uses('AppController', 'Controller'); 

class UsersController extends AppController { 

  public $layout = "auth"; 

  public $components = array( 
    'Paginator', 
    // load the BotDetect Captcha component and set its parameter 
    'BotDetect.Captcha' => array( 
      'captchaConfig' => 'AuthCaptcha' 
    ) 
  ); 

  public function isAuthorized($user) { 
    if (isset($user['role']) && $user['role'] === 'admin') { 
      return true; 
    } 

    if (in_array($this->action, array('edit', 'delete'))) { 
      if ($this->request->params['pass'][0] == $user['id']) { 
        return true; 
      } 
    } 
    return false; 
  } 

  public function beforeFilter() { 
    parent::beforeFilter(); 
    $this->Auth->allow('add'); 

    $this->Security->validatePost = false; 
  } 

  public function login() { 

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

      // clear previous user input, since each Captcha code can only be validated once 
      unset($this->request->data['User']['CaptchaCode']); 

      if ($isHuman && $this->Auth->login()) { 
        // Captcha validation passed and login successful 
        return $this->redirect($this->Auth->redirectUrl()); 
      } else { 
        if (!$isHuman) { 
          // Captcha validation failed, return an error message 
          $this->Session->setFlash(__('CAPTCHA validation failed, try again.')); 
        } else { 
          $this->Session->setFlash(__('Invalid username or password, try again')); 
        } 
      } 
    } 
  } 

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

  public function index() { 
    $this->User->recursive = 0; 
    $this->set('users', $this->Paginator->paginate()); 
  } 

  public function view($id = null) { 
    if (!$this->User->exists($id)) { 
      throw new NotFoundException(__('Invalid user')); 
    } 
    $options = array('conditions' => array('User.' . $this->User->primaryKey => $id)); 
    $this->set('user', $this->User->find('first', $options)); 
  } 

  public function add() { 
    // not show and validate captcha when logged in 
    if ($this->Auth->loggedIn()) { 

      if ($this->request->is('post')) { 
        $this->User->create(); 
        if ($this->User->save($this->request->data)) { 
          // Captcha validation passed and save successful 
          $this->Session->setFlash(__('The user has been saved.')); 
          return $this->redirect(array('action' => 'index')); 
        } else { 
          $this->Session->setFlash(__('The user could not be saved. Please, try again.')); 
        } 
      } 

    } else { 

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

        // clear previous user input, since each Captcha code can only be validated once 
        unset($this->request->data['User']['CaptchaCode']); 

        $this->User->create(); 
        if ($isHuman && $this->User->save($this->request->data)) { 
          // Captcha validation passed and save successful 
          $this->Session->setFlash(__('The user has been saved.')); 
          return $this->redirect(array('action' => 'index')); 
        } else { 
          if (!$isHuman) { 
            // Captcha validation failed, return an error message 
            $this->Session->setFlash(__('CAPTCHA validation failed, try again.')); 
          } else { 
            $this->Session->setFlash(__('The user could not be saved. Please, try again.')); 
          } 
        } 
      } 
    } 
  } 

  public function edit($id = null) { 
    if (!$this->User->exists($id)) { 
      throw new NotFoundException(__('Invalid user')); 
    } 
    if ($this->request->is(array('post', 'put'))) { 
      if ($this->User->save($this->request->data)) { 
        $this->Session->setFlash(__('The user has been saved.')); 
        return $this->redirect(array('action' => 'index')); 
      } else { 
        $this->Session->setFlash(__('The user could not be saved. Please, try again.')); 
      } 
    } else { 
      $options = array('conditions' => array('User.' . $this->User->primaryKey => $id)); 
      $this->request->data = $this->User->find('first', $options); 
    } 
  } 

  public function delete($id = null) { 
    $this->User->id = $id; 
    if (!$this->User->exists()) { 
      throw new NotFoundException(__('Invalid user')); 
    } 
    $this->request->allowMethod('post', 'delete'); 
    if ($this->User->delete()) { 
      $this->Session->setFlash(__('The user has been deleted.')); 
    } else { 
      $this->Session->setFlash(__('The user could not be deleted. Please, try again.')); 
    } 
    return $this->redirect(array('action' => 'index')); 
  } 
  
} 

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

Loading the required helpers and BotDetect Captcha component.

Method: login()

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: add()

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

Captcha is hidden and validation doesn't occur for users that are already logged in.