I needed to create a couple of forms for my latest project using the Codeigniter (CI) framework. For those who have worked with CI before, it has many neat classes built in – including Captcha. Captcha is the bot prevention mechanism you see in many web forms. Bot prevention meaning – you have to be human to actually read the letters in the image.
These letters have to be submitted to the web server, check if the values match. If it does, then process the information… or else, you must be a bot.
As mentioned, CI has already done the leg work in creating the fuzzy image with the letters. This is called the Captcha helper. All you need to do is pass an array of options then voila! Your image is created. This tutorial will teach you how to wrap this functionality in our own class, so additional methods can be hooked up to it. This will make our wrapper encapsulated and reusable for as many forms as we need within our application.
Note that I’m assuming that you’ve worked with CI before, or have experience with MVC, or even just object oriented programming. Ready to get started? Let’s begin:
In our application/libraries folder, create a new file and name it Mycaptcha.php. Let’s create our class and name it Mycaptcha. Inside, let’s define a couple of variables for later use, add our constructor method which creates $CI. $CI is to ensure that we’re dealing with the same object we use from within our controllers.
class Mycaptcha { public $word = ''; public $ci = ''; public function __construct() { $CI = & get_instance(); $CI->load->helper('captcha'); $this->ci = $CI; } }
Next, let’s create a method to create the random words in the image.
public function createWord(){ $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $word = ''; for ($a = 0; $a <= 5; $a++) { $b = rand(0, strlen($chars) - 1); $word .= $chars[$b]; } $this->word = $word; return $this; }
Now we have 2 properties accessible throughout our class (ci and word). Let’s go ahead and create the Captcha image using CI’s helper:
public function createCaptcha(){ $cap = array( 'word' => $this->word, 'img_path' => './httpdocs/captcha/', //this is your directory 'img_url' => base_url() . 'httpdocs/captcha/', 'img_width' => '150', 'img_height' => '30', 'expiration' => '7200' ); $captchaOutput = create_captcha($cap); $this->ci->session->set_userdata(array('word'=>$this->word, 'image' => $captchaOutput['time'].'.jpg')); //set data to session for compare return $captchaOutput['image']; }
Notice that we’re using the 2 properties that I mentioned. Also, make sure you have a folder with write permissions somewhere in your application. Above – I have it in ‘./httpdocs/captcha/’ – which goes outside of our application folder. This is where the images will be saved. Another thing to notice here – I’m saving the word and the jpg name in session using CI’s session class (line 13 above). This will make it easier for us to check the value for form submission and have the image name as well (for cleanup).
Our last method is to delete the image that we’ve created. The code is below:
public function deleteImage(){ if(isset($this->ci->session->userdata['image'])){ $lastImage = FCPATH . "httpdocs/captcha/" . $this->ci->session->userdata['image']; if(file_exists($lastImage)){ unlink($lastImage); } } return $this; }
Adding Captcha to Form Validation
Now we have our class, we need a way to check the values against our form field. Let’s create a new file and call it MY_Form_validation.php and save it in libraries folder. Here, we are extending the form validation class in CI.
class MY_Form_validation extends CI_Form_validation { public function validate_captcha($word) { $CI = & get_instance(); if(empty($word) || $word != $CI->session->userdata['word']){ $CI->form_validation->set_message('validate_captcha', 'The letters you entered do not match the image.'); return FALSE; }else{ return TRUE; } } }
The method above simply checks the parameter ($word) against the value set in our session (from our class). It also set an error message so we can present it nicely. Finally, let’s get to our controller to make it all stick.
$this->form_validation ->set_rules('captcha', 'Captcha', 'required|validate_captcha'); //above is our custom validation $this->load->library('mycaptcha'); //this is our wrapper if ($this->form_validation->run() == FALSE) { $data['captcha'] = $this->mycaptcha ->deleteImage() //these are the 3 methods ->createWord() ->createCaptcha(); $this->load->view('YOURVIEW.php', $data); } else { $this->mycaptcha->deleteImage(); //delete image again $this->session->set_flashdata(array('message' => 'Your message was sent successfully', 'type' => 'success')); redirect('YOURSUCCESSPAGE.php'); }
As you see, we kept our controller straight to the point. We pass our ‘validate_captcha’ in CI’s set rules, along with the input field name (line 1). We load our wrapper, runs the validation and the 3 methods from our class. Notice deleteImage() runs in the else clause as well? That’s because we delete the image even if it’s successful to keep our directory clean.
All we have to do is call it in our form like so:
Conclusion
Our wrapper can be now reused in all our forms. I especially like that in our controller, all we need to do is:
$this->mycaptcha->deleteImage()->createWord()->createCaptcha() – which will run all our methods fluently.
Questions? Please feel free to leave them below.
thank you. I didn’t know that. so how would you modify – not use ci session?
i’ve just encrypt the cookie
$config[‘sess_encrypt_cookie’] = TRUE;
i don’t know it 100% save. at least it more complicated for user to change the value.
by the way, thanks man for your nice article
hi, thanks for nice tutorial but When I run your code then show me following error message: Fatal error: Call to undefined function create_captcha() in F:xampphtdocsdhuronto_omsapplicationlibrariesMycaptcha.php on line 33
make sure you load the library
Thanks!