CodeIgniter 3 Ion Auth CAPTCHA code example

CodeIgniter Ion Auth CAPTCHA Example demonstrates how to integrate BotDetect PHP Captcha into login, register and reset password forms in a scenario where Ion 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_ion_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 forgot password page
  'ForgotPasswordCaptcha' => array(
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(3, 6),
    'CustomLightColor' => '#9966FF',
  ),

);

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

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

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

<h1><?php echo lang('login_heading');?></h1>
<p><?php echo lang('login_subheading');?></p>

<div><?php echo $captchaValidationMessage;?></div>
<div id="infoMessage"><?php echo $message;?></div>

<?php echo form_open("auth/login");?>

  <p>
    <?php echo lang('login_identity_label', 'identity');?>
    <?php echo form_input($identity);?>
  </p>

  <p>
    <?php echo lang('login_password_label', 'password');?>
    <?php echo form_input($password);?>
  </p>

  <p>
    <label for="CaptchaCode">Please retype the characters from the image:</label>
    <?php 
      $botdetectCaptcha = array(
        'name'        => 'CaptchaCode',
        'id'          => 'CaptchaCode',
        'value'       => '',
        'maxlength'   => '100',
        'size'        => '50'
      );
      // Show captcha image
      echo $captchaHtml; 
      echo form_input($botdetectCaptcha);
    ?>
  </p>

  <p>
    <?php echo lang('login_remember_label', 'remember');?>
    <?php echo form_checkbox('remember', '1', FALSE, 'id="remember"');?>
  </p>

  <p><?php echo form_submit('submit', lang('login_submit_btn'));?></p>

<?php echo form_close();?>

<p><a href="forgot_password"><?php echo lang('login_forgot_password');?></a></p>

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 auth Controller).

View – /application/views/auth/forgot_password.php

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

<h1><?php echo lang('forgot_password_heading');?></h1>
<p><?php echo sprintf(lang('forgot_password_subheading'), $identity_label);?></p>

<div><?php echo $captchaValidationMessage; ?></div>
<div id="infoMessage"><?php echo $message;?></div>

<?php echo form_open("auth/forgot_password");?>

      <p>
        <label for="email"><?php echo sprintf(lang('forgot_password_email_label'), 
        $identity_label);?></label> <br />
        <?php echo form_input($email);?>
      </p>

      <p>
      <label for="CaptchaCode">Please retype the characters from the image:</label>
      <?php 
        $botdetectCaptcha = array(
          'name'        => 'CaptchaCode',
          'id'          => 'CaptchaCode',
          'value'       => '',
          'maxlength'   => '100',
          'size'        => '50'
        );
        // Show captcha image
        echo $captchaHtml; 
        echo form_input($botdetectCaptcha);
      ?>
    </p>

      <p><?php echo form_submit('submit', lang('forgot_password_submit_btn'));?></p>

<?php echo form_close();?>

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 forgot_password() method of the auth Controller).

Controller – /application/controllers/Auth.php

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

class Auth extends CI_Controller {

  function __construct()
  {
    parent::__construct();
    $this->load->library('ion_auth');
    $this->load->library('form_validation');
    $this->load->helper('url');
    $this->load->helper('form');

    $this->load->database();

    $this->form_validation->set_error_delimiters($this->config->item('error_start_delimiter', 'ion_auth'), $this->config->item('error_end_delimiter', 'ion_auth'));

    $this->lang->load('auth');
    $this->load->helper('language');
  }

  //redirect if needed, otherwise display the user list
  function index()
  {
    if (!$this->ion_auth->logged_in())
    {
      //redirect them to the login page
      redirect('auth/login', 'refresh');
    }
    elseif (!$this->ion_auth->is_admin()) //remove this elseif if you want to enable this for non-admins
    {
      //redirect them to the home page because they must be an administrator to view this
      return show_error('You must be an administrator to view this page.');
    }
    else
    {
      //set the flash data error message if there is one
      $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');

      //list the users
      $this->data['users'] = $this->ion_auth->users()->result();
      foreach ($this->data['users'] as $k => $user)
      {
        $this->data['users'][$k]->groups = $this->ion_auth->get_users_groups($user->id)->result();
      }

      $this->_render_page('auth/index', $this->data);
    }
  }

  //log the user in
  function login()
  {
    $this->data['title'] = "Login";

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

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

    //validate form input
    $this->form_validation->set_rules('identity', 'Identity', 'required');
    $this->form_validation->set_rules('password', 'Password', 'required');


    if ($this->form_validation->run() == true)
    {
      //check to see if the user is logging in
      //check for "remember me"
      $remember = (bool) $this->input->post('remember');

      // 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->ion_auth->login($this->input->post('identity'), $this->input->post('password'), $remember))
      {
        //if the login is successful
        //redirect them back to the home page
        $this->session->set_flashdata('message', $this->ion_auth->messages());
        redirect(base_url(). 'auth', 'refresh');
      }
      else
      {
        //if the login was un-successful
        //redirect them back to the login page

        // Captcha validation failed, show error message
        if (!$isHuman) {
          $this->session->set_flashdata('captchaValidationMessage', 'CAPTCHA validation failed, please try again.');
        }

        $this->session->set_flashdata('message', $this->ion_auth->errors());
        redirect('auth/login', 'refresh'); //use redirects instead of loading views for compatibility with MY_Controller libraries
      }
    }
    else
    {
      // make Captcha Html accessible to View code
      $this->data['captchaHtml'] = $this->botdetectcaptcha->Html();
      $this->data['captchaValidationMessage'] = ($this->session->flashdata('captchaValidationMessage'))? $this->session->flashdata('captchaValidationMessage') : '';


      //the user is not logging in so display the login page
      //set the flash data error message if there is one
      $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');

      $this->data['identity'] = array('name' => 'identity',
        'id' => 'identity',
        'type' => 'text',
        'value' => $this->form_validation->set_value('identity'),
      );
      $this->data['password'] = array('name' => 'password',
        'id' => 'password',
        'type' => 'password',
      );

      $this->_render_page('auth/login', $this->data);
    }
  }

  //log the user out
  function logout()
  {
    $this->data['title'] = "Logout";

    //log the user out
    $logout = $this->ion_auth->logout();

    //redirect them to the login page
    $this->session->set_flashdata('message', $this->ion_auth->messages());
    redirect('auth/login', 'refresh');
  }

  //change password
  function change_password()
  {
    $this->form_validation->set_rules('old', $this->lang->line('change_password_validation_old_password_label'), 'required');
    $this->form_validation->set_rules('new', $this->lang->line('change_password_validation_new_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[new_confirm]');
    $this->form_validation->set_rules('new_confirm', $this->lang->line('change_password_validation_new_password_confirm_label'), 'required');

    if (!$this->ion_auth->logged_in())
    {
      redirect('auth/login', 'refresh');
    }

    $user = $this->ion_auth->user()->row();

    if ($this->form_validation->run() == false)
    {
      //display the form
      //set the flash data error message if there is one
      $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');

      $this->data['min_password_length'] = $this->config->item('min_password_length', 'ion_auth');
      $this->data['old_password'] = array(
        'name' => 'old',
        'id'   => 'old',
        'type' => 'password',
      );
      $this->data['new_password'] = array(
        'name' => 'new',
        'id'   => 'new',
        'type' => 'password',
        'pattern' => '^.{'.$this->data['min_password_length'].'}.*$',
      );
      $this->data['new_password_confirm'] = array(
        'name' => 'new_confirm',
        'id'   => 'new_confirm',
        'type' => 'password',
        'pattern' => '^.{'.$this->data['min_password_length'].'}.*$',
      );
      $this->data['user_id'] = array(
        'name'  => 'user_id',
        'id'    => 'user_id',
        'type'  => 'hidden',
        'value' => $user->id,
      );

      //render
      $this->_render_page('auth/change_password', $this->data);
    }
    else
    {
      $identity = $this->session->userdata('identity');

      $change = $this->ion_auth->change_password($identity, $this->input->post('old'), $this->input->post('new'));

      if ($change)
      {
        //if the password was successfully changed
        $this->session->set_flashdata('message', $this->ion_auth->messages());
        $this->logout();
      }
      else
      {
        $this->session->set_flashdata('message', $this->ion_auth->errors());
        redirect('auth/change_password', 'refresh');
      }
    }
  }

  //forgot password
  function forgot_password()
  {
    // load the BotDetect Captcha library and set its parameter
    $this->load->library('botdetect/BotDetectCaptcha', array(
      'captchaConfig' => 'ForgotPasswordCaptcha'
    ));

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

    $this->form_validation->set_rules('email', $this->lang->line('forgot_password_validation_email_label'), 'required|valid_email');

    if ($this->form_validation->run() == false)
    {

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

      //setup the input
      $this->data['email'] = array('name' => 'email',
        'id' => 'email',
      );

      if ( $this->config->item('identity', 'ion_auth') == 'username' ){
        $this->data['identity_label'] = $this->lang->line('forgot_password_username_identity_label');
      }
      else
      {
        $this->data['identity_label'] = $this->lang->line('forgot_password_email_identity_label');
      }

      //set any errors and display the form
      $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');
      $this->_render_page('auth/forgot_password', $this->data);
    }
    else
    {
      // 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 failed, show error message
        $this->session->set_flashdata('captchaValidationMessage', 'CAPTCHA validation failed, please try again.');
        redirect("auth/forgot_password", 'refresh');
      }

      // get identity from username or email
      if ( $this->config->item('identity', 'ion_auth') == 'username' ){
        $identity = $this->ion_auth->where('username', strtolower($this->input->post('email')))->users()->row();
      }
      else
      {
        $identity = $this->ion_auth->where('email', strtolower($this->input->post('email')))->users()->row();
      }

      if(empty($identity)) {
        $this->ion_auth->set_message('forgot_password_email_not_found');
        $this->session->set_flashdata('message', $this->ion_auth->messages());
        redirect("auth/forgot_password", 'refresh');
      }

      //run the forgotten password method to email an activation code to the user
      $forgotten = $this->ion_auth->forgotten_password($identity->{$this->config->item('identity', 'ion_auth')});

      if ($forgotten)
      {
        //if there were no errors
        $this->session->set_flashdata('message', $this->ion_auth->messages());
        redirect("auth/login", 'refresh'); //we should display a confirmation page here instead of the login page
      }
      else
      {
        $this->session->set_flashdata('message', $this->ion_auth->errors());
        redirect("auth/forgot_password", 'refresh');
      }
    }
  }

  //reset password - final step for forgotten password
  public function reset_password($code = NULL)
  {
    if (!$code)
    {
        show_404();
    }

    $user = $this->ion_auth->forgotten_password_check($code);

    if ($user)
    {
      //if the code is valid then display the password reset form

      $this->form_validation->set_rules('new', $this->lang->line('reset_password_validation_new_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[new_confirm]');
      $this->form_validation->set_rules('new_confirm', $this->lang->line('reset_password_validation_new_password_confirm_label'), 'required');

      if ($this->form_validation->run() == false)
      {
        //display the form

        //set the flash data error message if there is one
        $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');

        $this->data['min_password_length'] = $this->config->item('min_password_length', 'ion_auth');
        $this->data['new_password'] = array(
          'name' => 'new',
          'id'   => 'new',
          'type' => 'password',
          'pattern' => '^.{'.$this->data['min_password_length'].'}.*$',
        );
        $this->data['new_password_confirm'] = array(
          'name' => 'new_confirm',
          'id'   => 'new_confirm',
          'type' => 'password',
          'pattern' => '^.{'.$this->data['min_password_length'].'}.*$',
        );
        $this->data['user_id'] = array(
          'name'  => 'user_id',
          'id'    => 'user_id',
          'type'  => 'hidden',
          'value' => $user->id,
        );
        $this->data['csrf'] = $this->_get_csrf_nonce();
        $this->data['code'] = $code;

        //render
        $this->_render_page('auth/reset_password', $this->data);
      }
      else
      {
        // do we have a valid request?
        if ($this->_valid_csrf_nonce() === FALSE || $user->id != $this->input->post('user_id'))
        {

          //something fishy might be up
          $this->ion_auth->clear_forgotten_password_code($code);

          show_error($this->lang->line('error_csrf'));

        }
        else
        {
          // finally change the password
          $identity = $user->{$this->config->item('identity', 'ion_auth')};

          $change = $this->ion_auth->reset_password($identity, $this->input->post('new'));

          if ($change)
          {
            //if the password was successfully changed
            $this->session->set_flashdata('message', $this->ion_auth->messages());
            $this->logout();
          }
          else
          {
            $this->session->set_flashdata('message', $this->ion_auth->errors());
            redirect('auth/reset_password/' . $code, 'refresh');
          }
        }
      }
    }
    else
    {
      //if the code is invalid then send them back to the forgot password page
      $this->session->set_flashdata('message', $this->ion_auth->errors());
      redirect("auth/forgot_password", 'refresh');
    }
  }


  //activate the user
  function activate($id, $code=false)
  {
    if ($code !== false)
    {
      $activation = $this->ion_auth->activate($id, $code);
    }
    else if ($this->ion_auth->is_admin())
    {
      $activation = $this->ion_auth->activate($id);
    }

    if ($activation)
    {
      //redirect them to the auth page
      $this->session->set_flashdata('message', $this->ion_auth->messages());
      redirect("auth", 'refresh');
    }
    else
    {
      //redirect them to the forgot password page
      $this->session->set_flashdata('message', $this->ion_auth->errors());
      redirect("auth/forgot_password", 'refresh');
    }
  }

  //deactivate the user
  function deactivate($id = NULL)
  {
    $id = (int) $id;

    $this->load->library('form_validation');
    $this->form_validation->set_rules('confirm', $this->lang->line('deactivate_validation_confirm_label'), 'required');
    $this->form_validation->set_rules('id', $this->lang->line('deactivate_validation_user_id_label'), 'required|alpha_numeric');

    if ($this->form_validation->run() == FALSE)
    {
      // insert csrf check
      $this->data['csrf'] = $this->_get_csrf_nonce();
      $this->data['user'] = $this->ion_auth->user($id)->row();

      $this->_render_page('auth/deactivate_user', $this->data);
    }
    else
    {
      // do we really want to deactivate?
      if ($this->input->post('confirm') == 'yes')
      {
        // do we have a valid request?
        if ($this->_valid_csrf_nonce() === FALSE || $id != $this->input->post('id'))
        {
          show_error($this->lang->line('error_csrf'));
        }

        // do we have the right userlevel?
        if ($this->ion_auth->logged_in() && $this->ion_auth->is_admin())
        {
          $this->ion_auth->deactivate($id);
        }
      }

      //redirect them back to the auth page
      redirect('auth', 'refresh');
    }
  }

  //create a new user
  function create_user()
  {
    $this->data['title'] = "Create User";

    if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin())
    {
      redirect('auth', 'refresh');
    }

    $tables = $this->config->item('tables','ion_auth');

    //validate form input
    $this->form_validation->set_rules('first_name', $this->lang->line('create_user_validation_fname_label'), 'required|xss_clean');
    $this->form_validation->set_rules('last_name', $this->lang->line('create_user_validation_lname_label'), 'required|xss_clean');
    $this->form_validation->set_rules('email', $this->lang->line('create_user_validation_email_label'), 'required|valid_email|is_unique['.$tables['users'].'.email]');
    $this->form_validation->set_rules('phone', $this->lang->line('create_user_validation_phone_label'), 'required|xss_clean');
    $this->form_validation->set_rules('company', $this->lang->line('create_user_validation_company_label'), 'required|xss_clean');
    $this->form_validation->set_rules('password', $this->lang->line('create_user_validation_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[password_confirm]');
    $this->form_validation->set_rules('password_confirm', $this->lang->line('create_user_validation_password_confirm_label'), 'required');

    if ($this->form_validation->run() == true)
    {
      $username = strtolower($this->input->post('first_name')) . ' ' . strtolower($this->input->post('last_name'));
      $email    = strtolower($this->input->post('email'));
      $password = $this->input->post('password');

      $additional_data = array(
        'first_name' => $this->input->post('first_name'),
        'last_name'  => $this->input->post('last_name'),
        'company'    => $this->input->post('company'),
        'phone'      => $this->input->post('phone'),
      );
    }
    if ($this->form_validation->run() == true && $this->ion_auth->register($username, $password, $email, $additional_data))
    {
      //check to see if we are creating the user
      //redirect them back to the admin page
      $this->session->set_flashdata('message', $this->ion_auth->messages());
      redirect("auth", 'refresh');
    }
    else
    {
      //display the create user form
      //set the flash data error message if there is one
      $this->data['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message')));

      $this->data['first_name'] = array(
        'name'  => 'first_name',
        'id'    => 'first_name',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('first_name'),
      );
      $this->data['last_name'] = array(
        'name'  => 'last_name',
        'id'    => 'last_name',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('last_name'),
      );
      $this->data['email'] = array(
        'name'  => 'email',
        'id'    => 'email',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('email'),
      );
      $this->data['company'] = array(
        'name'  => 'company',
        'id'    => 'company',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('company'),
      );
      $this->data['phone'] = array(
        'name'  => 'phone',
        'id'    => 'phone',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('phone'),
      );
      $this->data['password'] = array(
        'name'  => 'password',
        'id'    => 'password',
        'type'  => 'password',
        'value' => $this->form_validation->set_value('password'),
      );
      $this->data['password_confirm'] = array(
        'name'  => 'password_confirm',
        'id'    => 'password_confirm',
        'type'  => 'password',
        'value' => $this->form_validation->set_value('password_confirm'),
      );

      $this->_render_page('auth/create_user', $this->data);
    }
  }

  //edit a user
  function edit_user($id)
  {
    $this->data['title'] = "Edit User";

    if (!$this->ion_auth->logged_in() || (!$this->ion_auth->is_admin() && !($this->ion_auth->user()->row()->id == $id)))
    {
      redirect('auth', 'refresh');
    }

    $user = $this->ion_auth->user($id)->row();
    $groups=$this->ion_auth->groups()->result_array();
    $currentGroups = $this->ion_auth->get_users_groups($id)->result();

    //validate form input
    $this->form_validation->set_rules('first_name', $this->lang->line('edit_user_validation_fname_label'), 'required|xss_clean');
    $this->form_validation->set_rules('last_name', $this->lang->line('edit_user_validation_lname_label'), 'required|xss_clean');
    $this->form_validation->set_rules('phone', $this->lang->line('edit_user_validation_phone_label'), 'required|xss_clean');
    $this->form_validation->set_rules('company', $this->lang->line('edit_user_validation_company_label'), 'required|xss_clean');
    $this->form_validation->set_rules('groups', $this->lang->line('edit_user_validation_groups_label'), 'xss_clean');

    if (isset($_POST) && !empty($_POST))
    {
      // do we have a valid request?
      if ($this->_valid_csrf_nonce() === FALSE || $id != $this->input->post('id'))
      {
        show_error($this->lang->line('error_csrf'));
      }

      $data = array(
        'first_name' => $this->input->post('first_name'),
        'last_name'  => $this->input->post('last_name'),
        'company'    => $this->input->post('company'),
        'phone'      => $this->input->post('phone'),
      );

      // Only allow updating groups if user is admin
      if ($this->ion_auth->is_admin())
      {
        //Update the groups user belongs to
        $groupData = $this->input->post('groups');

        if (isset($groupData) && !empty($groupData)) {

          $this->ion_auth->remove_from_group('', $id);

          foreach ($groupData as $grp) {
            $this->ion_auth->add_to_group($grp, $id);
          }

        }
      }

      //update the password if it was posted
      if ($this->input->post('password'))
      {
        $this->form_validation->set_rules('password', $this->lang->line('edit_user_validation_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[password_confirm]');
        $this->form_validation->set_rules('password_confirm', $this->lang->line('edit_user_validation_password_confirm_label'), 'required');

        $data['password'] = $this->input->post('password');
      }

      if ($this->form_validation->run() === TRUE)
      {
        $this->ion_auth->update($user->id, $data);

        //check to see if we are creating the user
        //redirect them back to the admin page
        $this->session->set_flashdata('message', "User Saved");
        if ($this->ion_auth->is_admin())
        {
          redirect('auth', 'refresh');
        }
        else
        {
          redirect('/', 'refresh');
        }
      }
    }

    //display the edit user form
    $this->data['csrf'] = $this->_get_csrf_nonce();

    //set the flash data error message if there is one
    $this->data['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message')));

    //pass the user to the view
    $this->data['user'] = $user;
    $this->data['groups'] = $groups;
    $this->data['currentGroups'] = $currentGroups;

    $this->data['first_name'] = array(
        'name'  => 'first_name',
        'id'    => 'first_name',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('first_name', $user->first_name),
    );
    $this->data['last_name'] = array(
        'name'  => 'last_name',
        'id'    => 'last_name',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('last_name', $user->last_name),
    );
    $this->data['company'] = array(
        'name'  => 'company',
        'id'    => 'company',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('company', $user->company),
    );
    $this->data['phone'] = array(
        'name'  => 'phone',
        'id'    => 'phone',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('phone', $user->phone),
    );
    $this->data['password'] = array(
        'name' => 'password',
        'id'   => 'password',
        'type' => 'password'
    );
    $this->data['password_confirm'] = array(
        'name' => 'password_confirm',
        'id'   => 'password_confirm',
        'type' => 'password'
    );

    $this->_render_page('auth/edit_user', $this->data);
  }

  // create a new group
  function create_group()
  {
    $this->data['title'] = $this->lang->line('create_group_title');

    if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin())
    {
      redirect('auth', 'refresh');
    }

    //validate form input
    $this->form_validation->set_rules('group_name', $this->lang->line('create_group_validation_name_label'), 'required|alpha_dash|xss_clean');
    $this->form_validation->set_rules('description', $this->lang->line('create_group_validation_desc_label'), 'xss_clean');

    if ($this->form_validation->run() == TRUE)
    {
      $new_group_id = $this->ion_auth->create_group($this->input->post('group_name'), $this->input->post('description'));
      if($new_group_id)
      {
        // check to see if we are creating the group
        // redirect them back to the admin page
        $this->session->set_flashdata('message', $this->ion_auth->messages());
        redirect("auth", 'refresh');
      }
    }
    else
    {
      //display the create group form
      //set the flash data error message if there is one
      $this->data['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message')));

      $this->data['group_name'] = array(
        'name'  => 'group_name',
        'id'    => 'group_name',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('group_name'),
      );
      $this->data['description'] = array(
        'name'  => 'description',
        'id'    => 'description',
        'type'  => 'text',
        'value' => $this->form_validation->set_value('description'),
      );

      $this->_render_page('auth/create_group', $this->data);
    }
  }

  //edit a group
  function edit_group($id)
  {
    // bail if no group id given
    if(!$id || empty($id))
    {
      redirect('auth', 'refresh');
    }

    $this->data['title'] = $this->lang->line('edit_group_title');

    if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin())
    {
      redirect('auth', 'refresh');
    }

    $group = $this->ion_auth->group($id)->row();

    //validate form input
    $this->form_validation->set_rules('group_name', $this->lang->line('edit_group_validation_name_label'), 'required|alpha_dash|xss_clean');
    $this->form_validation->set_rules('group_description', $this->lang->line('edit_group_validation_desc_label'), 'xss_clean');

    if (isset($_POST) && !empty($_POST))
    {
      if ($this->form_validation->run() === TRUE)
      {
        $group_update = $this->ion_auth->update_group($id, $_POST['group_name'], $_POST['group_description']);

        if($group_update)
        {
          $this->session->set_flashdata('message', $this->lang->line('edit_group_saved'));
        }
        else
        {
          $this->session->set_flashdata('message', $this->ion_auth->errors());
        }
        redirect("auth", 'refresh');
      }
    }

    //set the flash data error message if there is one
    $this->data['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message')));

    //pass the user to the view
    $this->data['group'] = $group;

    $this->data['group_name'] = array(
      'name'  => 'group_name',
      'id'    => 'group_name',
      'type'  => 'text',
      'value' => $this->form_validation->set_value('group_name', $group->name),
    );
    $this->data['group_description'] = array(
      'name'  => 'group_description',
      'id'    => 'group_description',
      'type'  => 'text',
      'value' => $this->form_validation->set_value('group_description', $group->description),
    );

    $this->_render_page('auth/edit_group', $this->data);
  }


  function _get_csrf_nonce()
  {
    $this->load->helper('string');
    $key   = random_string('alnum', 8);
    $value = random_string('alnum', 20);
    $this->session->set_flashdata('csrfkey', $key);
    $this->session->set_flashdata('csrfvalue', $value);

    return array($key => $value);
  }

  function _valid_csrf_nonce()
  {
    if ($this->input->post($this->session->flashdata('csrfkey')) !== FALSE &&
            $this->input->post($this->session->flashdata('csrfkey')) == $this->session->flashdata('csrfvalue'))
    {
      return TRUE;
    }
    else
    {
      return FALSE;
    }
  }

  function _render_page($view, $data=null, $render=false)
  {

    $this->viewdata = (empty($data)) ? $this->data: $data;

    $view_html = $this->load->view($view, $this->viewdata, $render);

    if (!$render) return $view_html;
  }

}

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 $this->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.

- forgot_password() 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 $this->data array.

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