CodeIgniter 3 Bit Auth CAPTCHA code example

CodeIgniter Bit Auth CAPTCHA Example demonstrates how to integrate BotDetect PHP Captcha into login, register and reset password forms in a scenario where Bit Auth library is used to authenticate users to your application.

First Time Here?

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

Alongside the Captcha image, the user is provided with an input field to retype the displayed characters. Depending on if the Captcha code entered matches the displayed one or not, a message stating the validation result is shown on the form.

The simple code showing the message in this example would of course be replaced with useful form processing code in a real world scenario.

Files for this ('codeigniter_bit_auth_captcha_example') example are:

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

Routing – /application/config/routes.php

$route['botdetect/captcha-handler'] = 'botdetect/captcha_handler/index';

In the code above we have registered default route of the Captcha library.

Config – /application/config/captcha.php

<?php
// BotDetect PHP Captcha configuration options

$config = array(
  // Captcha configuration for login page
  'LoginCaptcha' => array(
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 6),
    'ImageStyle' => array(
      ImageStyle::Radar,
      ImageStyle::Collage,
      ImageStyle::Fingerprints,
    ),
  ),

  // Captcha configuration for register page
  'RegisterCaptcha' => array(
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 7),
    'CodeStyle' => CodeStyle::Alpha,
  ),

);

In order to use the BotDetect CAPTCHA CodeIgniter Library, we have declared Captcha configuration which will be used when loading the library in ExampleController. Detailed description of this approach is available in a BotDetect CodeIgniter 3 integration guide.

View – /application/views/example/login.php

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <style type="text/css">
    body { margin: 0; padding: 0; font-size: 10pt; font-family: Verdana, Arial, sans-
    serif; }
    form { width: 400px; margin: 0 auto; padding: 10px; border: 1px solid #666; }
    label, input[type=text], input[type=password] { display: block; width: 100%; }
    input { margin-bottom: 8px; }
    #bottom { width: 420px; padding: 10px 0; margin: 0 auto; }
    #header { font-size: 1.4em; font-weight: bold; width: 420px; margin: 60px auto 0 
    auto; text-align: center; }
    .error { color: #940D0A; font-weight: bold; }
  </style>
  <title>BitAuth: Login</title>

  <link type="text/css" rel="Stylesheet" href="<?php echo CaptchaUrls::
    LayoutStylesheetUrl() ?>" />


</head>
<body>
<?php
  echo '<div id="header">BitAuth Example: Login</div>';

  echo form_open(current_url());
  echo form_label('Username','username');
  echo form_input('username');
  echo form_label('Password','password');
  echo form_password('password');

  
  // Show captcha image
  echo $captchaHtml; 

  $botdetectCaptcha = array(
    'name'        => 'CaptchaCode',
    'id'          => 'CaptchaCode',
    'value'       => '',
    'maxlength'   => '100',
    'size'        => '50'
  );
  echo form_input($botdetectCaptcha);

  echo form_label(form_checkbox('remember_me', 1).' Remember Me', 'remember_me');
  echo form_submit('login','Login');
  echo ( ! empty($error) ? $error : '' );

  
  // Show captcha error message
  echo ( ! empty($captchaValidationMessage)? $captchaValidationMessage : '' );
  
  echo form_close();

  echo '<div id="bottom">';
  echo '<span style="float: right;">'.anchor('example/register', 'Register').'</span>';
  echo 'Username: <strong>admin</strong><br/>Password: <strong>admin</strong>';
  echo '</div>';

?>
</body>
</html>

The above code uses the CodeIgniter form helpers to generate a form, although the actual form can be created in many other ways. The only requirement is that the form contains an input field of your choice where the user can retype the characters shown in the Captcha image. This user-entered code should be available to you in Controller code after form submission.

Note that the action of the form points to the same action of the Controller the View belongs to. Also, the name of the input field corresponds to the variable in the request object that we will use for validation in the Controller.

The Captcha markup made available in the Controller is used in the View to compose a simple form with one input field and a Captcha image. The View utilizes a BotDetect supplied Css helper method to add the required stylesheet. Finally, it prints out a message about the Captcha validation status (set in the login() method of the example Controller).

View – /application/views/example/add_user.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.
org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <style type="text/css">
    body { margin: 0; padding: 0; font-size: 10pt; font-family: Verdana, Arial, sans-
    serif; }
    #bottom { width: 600px; padding: 10px; margin: 0 auto; }
    #table { width: 600px; margin: 60px auto 0 auto; border-left: 1px solid #666; 
    border-bottom: 1px solid #666; }
    #table td, #table th { border: 1px solid #666; border-left: 0; border-bottom: 0; 
    padding: 6px; width: 50%; text-align: left; vertical-align: top; }
    #table td.label { text-align: right; }
    #table caption { font-size: 1.4em; font-weight: bold; }
    #table select, #table input[type=text], #table input[type=password] { width: 270px;
    }
    .error { color: #940D0A; font-weight: bold; }
  </style>
  <title>BitAuth: <?php echo $title; ?></title>

  <link type="text/css" rel="Stylesheet" href="<?php echo CaptchaUrls::
  LayoutStylesheetUrl() ?>" />
</head>
<body>
  <?php
    echo form_open(current_url());

    echo '<table border="0" cellspacing="0" cellpadding="0" id="table">';
    echo '<caption>BitAuth Example: '.$title.'</caption>';
    echo '<tr><td class="label">Username</td><td>'.form_input('username', set_value(
    'username')).'</td></tr>';
    echo '<tr><td class="label">Full Name</td><td>'.form_input('fullname', set_value(
    'fullname')).'</td></tr>';
    echo '<tr><td class="label">Email</td><td>'.form_input('email', set_value('email'))
    .'</td></tr>';
    echo '<tr><td class="label">Password</td><td>'.form_password('password').'</td><
    /tr>';
    echo '<tr><td class="label">Confirm Password</td><td>'.form_password(
    'password_conf').'</td></tr>';

    $botdetectCaptcha = array(
      'name'        => 'CaptchaCode',
      'id'          => 'CaptchaCode',
      'value'       => '',
      'maxlength'   => '100',
      'size'        => '50'
    );
    echo '<tr><td class="label">Captcha</td><td>';
    // Show captcha image
    echo $captchaHtml;
    echo form_input($botdetectCaptcha);
    echo '</td></tr>';

    // Show captcha error message
    if (!empty($captchaValidationMessage)) {
      echo '<tr><td colspan="2">'.$captchaValidationMessage.'</td></tr>';
    }

    if(validation_errors())
    {
      echo '<tr><td colspan="2">'.validation_errors().'</td></tr>';
    }

    echo '<tr><td class="label" colspan="2">'.form_submit('submit',$title).'</td></tr>
    ';
    echo '</table>';
    echo form_close();

    echo '<div id="bottom">';
    if(isset($bitauth) && $bitauth->logged_in())
    {
      echo anchor('example/logout', 'Logout', 'style="float: right;"');
    }
    else
    {
      echo anchor('example/login', 'Login', 'style="float: right;"');
    }
    echo '</div>';

  ?>
</body>
</html>

The above code uses the CodeIgniter form helpers to generate a form, although the actual form can be created in many other ways. The only requirement is that the form contains an input field of your choice where the user can retype the characters shown in the Captcha image. This user-entered code should be available to you in Controller code after form submission.

Note that the action of the form points to the same action of the Controller the View belongs to. Also, the name of the input field corresponds to the variable in the request object that we will use for validation in the Controller.

The Captcha markup made available in the Controller is used in the View to compose a simple form with one input field and a Captcha image. The View utilizes a BotDetect supplied Css helper method to add the required stylesheet. Finally, it prints out a message about the Captcha validation status (set in the register() method of the example Controller).

Controller – /application/controllers/Example.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Example extends CI_Controller
{

  /**
   * Example::__construct()
   *
   */
  public function __construct()
  {
    parent::__construct();

    $this->load->library('bitauth');

    $this->load->helper('form');
    $this->load->helper('url');

    $this->load->library('form_validation');
    $this->form_validation->set_error_delimiters('<div class="error">', '</div>');
  }

  /**
   * Example::convert()
   *
   */
  public function convert()
  {
    $this->load->dbforge();
    $this->dbforge->modify_column($this->bitauth->_table['groups'], array(
      'roles' => array(
        'name' => 'roles',
        'type' => 'text'
      )
    ));

    $query = $this->db->select('group_id, roles')->get($this->bitauth->_table['groups']);
    if($query && $query->num_rows())
    {
      foreach($query->result() as $row)
      {
        $this->db->where('group_id', $row->group_id)->set('roles', $this->bitauth->convert($row->roles))->update($this->bitauth->_table['groups']);
      }
    }

    echo 'Update complete.';
  }

  /**
   * Example::login()
   *
   */
  public function login()
  {
    $data = array();

    // load the BotDetect Captcha library and set its parameter
    $this->load->library('botdetect/BotDetectCaptcha', array(
      'captchaConfig' => 'LoginCaptcha'
    ));

    // make Captcha Html accessible to View code
    $data['captchaHtml'] = $this->botdetectcaptcha->Html();


    if($this->input->post())
    {
      // captcha code input field is required
      $this->form_validation->set_rules('CaptchaCode', 'Captcha Code', 'required');

      $this->form_validation->set_rules('username', 'Username', 'trim|required');
      $this->form_validation->set_rules('password', 'Password', 'required');
      $this->form_validation->set_rules('remember_me','Remember Me','');

      if($this->form_validation->run() == TRUE)
      {
        // validate the user-entered Captcha code when the form is submitted
        $code = $this->input->post('CaptchaCode');
        $isHuman = $this->botdetectcaptcha->Validate($code);

        // validate captcha and Login
        if($isHuman && $this->bitauth->login($this->input->post('username'), $this->input->post('password'), $this->input->post('remember_me')))
        {
          // Captcha validation correct and login successful

          // Redirect
          if($redir = $this->session->userdata('redir'))
          {
            $this->session->unset_userdata('redir');
          }

          redirect($redir ? $redir : 'example');
        }
        else
        {
          // Captcha validation failed, show error message
          if (!$isHuman) {
            $data['captchaValidationMessage'] = 'CAPTCHA validation failed, please try again.';
          }

          $data['error'] = $this->bitauth->get_error();
        }
      }
      else
      {
        $data['error'] = validation_errors();
      }
    }

    $this->load->view('example/login', $data);
  }

  /**
   * Example::index()
   *
   */
  public function index()
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    $this->load->view('example/users', array('bitauth' => $this->bitauth, 'users' => $this->bitauth->get_users()));
  }

  /**
  * Example::register()
  *
  */
  public function register()
  {
    $data = array();

    // load the BotDetect Captcha library and set its parameter
    $this->load->library('botdetect/BotDetectCaptcha', array(
      'captchaConfig' => 'RegisterCaptcha'
    ));

    // make Captcha Html accessible to View code
    $data['captchaHtml'] = $this->botdetectcaptcha->Html();


    if($this->input->post())
    {
      // captcha code input field is required
      $this->form_validation->set_rules('CaptchaCode', 'Captcha Code', 'required');

      $this->form_validation->set_rules('username', 'Username', 'trim|required|bitauth_unique_username');
      $this->form_validation->set_rules('fullname', 'Fullname', '');
      $this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email');
      $this->form_validation->set_rules('password', 'Password', 'required|bitauth_valid_password');
      $this->form_validation->set_rules('password_conf', 'Password Confirmation', 'required|matches[password]');

      if($this->form_validation->run() == TRUE)
      {
        // validate the user-entered Captcha code when the form is submitted
        $code = $this->input->post('CaptchaCode');
        $isHuman = $this->botdetectcaptcha->Validate($code);

        if ($isHuman) {
          // Captcha validation correct
          unset($_POST['submit'], $_POST['password_conf']);
          $this->bitauth->add_user($this->input->post());
          redirect('example/login');
        } else {
          // Captcha validation failed, show error message
          $data['captchaValidationMessage'] = 'CAPTCHA validation failed, please try again.';
        }
      }
    }

    $data['title'] = 'Register';

    $this->load->view('example/add_user', $data);
  }

  /**
  * Example::add_user()
  *
  */
  public function add_user()
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    if ( ! $this->bitauth->has_role('admin'))
    {
      $this->load->view('example/no_access');
      return;
    }

    if($this->input->post())
    {
      $this->form_validation->set_rules('username', 'Username', 'trim|required|bitauth_unique_username');
      $this->form_validation->set_rules('fullname', 'Fullname', '');
      $this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email');
      $this->form_validation->set_rules('password', 'Password', 'required|bitauth_valid_password');
      $this->form_validation->set_rules('password_conf', 'Password Confirmation', 'required|matches[password]');

      if($this->form_validation->run() == TRUE)
      {
        unset($_POST['submit'], $_POST['password_conf']);
        $this->bitauth->add_user($this->input->post());
        redirect('example');
      }

    }

    $this->load->view('example/add_user', array('title' => 'Add User', 'bitauth' => $this->bitauth));
  }


  /**
   * Example::edit_user()
   *
   */
  public function edit_user($user_id)
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    if ( ! $this->bitauth->has_role('admin'))
    {
      $this->load->view('example/no_access');
      return;
    }

    if($this->input->post())
    {
      $this->form_validation->set_rules('username', 'Username', 'trim|required|bitauth_unique_username['.$user_id.']');
      $this->form_validation->set_rules('fullname', 'Fullname', '');
      $this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email');
      $this->form_validation->set_rules('active', 'Active', '');
      $this->form_validation->set_rules('enabled', 'Enabled', '');
      $this->form_validation->set_rules('password_never_expires', 'Password Never Expires', '');
      $this->form_validation->set_rules('groups[]', 'Groups', '');

      if($this->input->post('password'))
      {
        $this->form_validation->set_rules('password', 'Password', 'bitauth_valid_password');
        $this->form_validation->set_rules('password_conf', 'Password Confirmation', 'required|matches[password]');
      }

      if($this->form_validation->run() == TRUE)
      {
        unset($_POST['submit'], $_POST['password_conf']);
        $this->bitauth->update_user($user_id, $this->input->post());
        redirect('example');
      }

    }

    $groups = array();
    foreach($this->bitauth->get_groups() as $_group)
    {
      $groups[$_group->group_id] = $_group->name;
    }


    $this->load->view('example/edit_user', array('bitauth' => $this->bitauth, 'groups' => $groups, 'user' => $this->bitauth->get_user_by_id($user_id)));
  }

  /**
   * Example::groups()
   *
   */
  public function groups()
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    $this->load->view('example/groups', array('bitauth' => $this->bitauth, 'groups' => $this->bitauth->get_groups()));
  }

  /**
   * Example::add_group()
   *
   */
  public function add_group()
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    if ( ! $this->bitauth->has_role('admin'))
    {
      $this->load->view('example/no_access');
      return;
    }

    if($this->input->post())
    {
      $this->form_validation->set_rules('name', 'Group Name', 'trim|required|bitauth_unique_group');
      $this->form_validation->set_rules('description', 'Description', '');
      $this->form_validation->set_rules('members[]', 'Members', '');
      $this->form_validation->set_rules('roles[]', 'Roles', '');

      if($this->form_validation->run() == TRUE)
      {
        unset($_POST['submit']);
        $this->bitauth->add_group($this->input->post());
        redirect('example/groups');
      }

    }

    $users = array();
    foreach($this->bitauth->get_users() as $_user)
    {
      $users[$_user->user_id] = $_user->fullname;
    }

    $this->load->view('example/add_group', array('bitauth' => $this->bitauth, 'roles' => $this->bitauth->get_roles(), 'users' => $users));
  }

  /**
   * Example:edit_group()
   *
   */
  public function edit_group($group_id)
  {
    if( ! $this->bitauth->logged_in())
    {
      $this->session->set_userdata('redir', current_url());
      redirect('example/login');
    }

    if ( ! $this->bitauth->has_role('admin'))
    {
      $this->load->view('example/no_access');
      return;
    }

    if($this->input->post())
    {
      $this->form_validation->set_rules('name', 'Group Name', 'trim|required|bitauth_unique_group['.$group_id.']');
      $this->form_validation->set_rules('description', 'Description', '');
      $this->form_validation->set_rules('members[]', 'Members', '');
      $this->form_validation->set_rules('roles[]', 'Roles', '');

      if($this->form_validation->run() == TRUE)
      {
        unset($_POST['submit']);
        $this->bitauth->update_group($group_id, $this->input->post());
        redirect('example/groups');
      }

    }

    $users = array();
    foreach($this->bitauth->get_users() as $_user)
    {
      $users[$_user->user_id] = $_user->fullname;
    }

    $group = $this->bitauth->get_group_by_id($group_id);

    $role_list = array();
    $roles = $this->bitauth->get_roles();
    foreach($roles as $_slug => $_desc)
    {
      if($this->bitauth->has_role($_slug, $group->roles))
      {
        $role_list[] = $_slug;
      }
    }

    $this->load->view('example/edit_group', array('bitauth' => $this->bitauth, 'roles' => $roles, 'group' => $group, 'group_roles' => $role_list, 'users' => $users));
  }

  /**
   * Example::activate()
   *
   */
  public function activate($activation_code)
  {
    if($this->bitauth->activate($activation_code))
    {
      $this->load->view('example/activation_successful');
      return;
    }

    $this->load->view('example/activation_failed');
  }

  /**
   * Example::logout()
   *
   */
  public function logout()
  {
    $this->bitauth->logout();
    redirect('example');
  }

}

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

- login() method:

After loading the required helpers and the BotDetect Captcha CodeIgniter library, the Html required for displaying the Captcha image and integrated controls is made available to the View by adding it to the $data array.

The sample form submits the data to the same Controller action that shows it (login), which is where we check the submitted data and pass it to the Validate() method of the Captcha library object.

- register() method:

After loading the required helpers and the BotDetect Captcha CodeIgniter library, the Html required for displaying the Captcha image and integrated controls is made available to the View by adding it to the $data array.

The sample form submits the data to the same Controller action that shows it (register), which is where we check the submitted data and pass it to the Validate() method of the Captcha library object.