Posted on May 14, 2008 by Elliott Brueggeman9 Comments »

Last November, I published a post on creating a simple PHP Captcha. Some readers noted that I actually used a more advanced captcha for my own site’s discussion pages, and asked for the source code. I’ve actually gone a step further and improved my own captcha by adding more background noise, decreasing the likelihood that a bot would be able to break it. Though harder for a bot to read, I changed the font and made it easier for a human to read.

As noted before, Captchas are images that are meant to tell the difference between a person and a computer, be presenting an image with text in it, and asking the user to enter the text and submit it with the form. Captchas are used to reduce spam on publicly accessible message boards and comment lists.

Below is the new and improved PHP captcha script and example implementation.

Requirements

To use this script, you will need PHP enabled web server with the Image (GD) extension enabled. If you are not sure, check with your hosting company. Most major hosting companies, like GoDaddy.com provide this by default.

Setup

On the page where your users are submitting content, like a post or a comment, you want to display the captcha and an input box for the user to enter the text displayed in the captcha. To use the PHP script below to you need to include it as an image on the page you want it to display – save the script as something like “advanced_captcha_script.php” and use the following html to display it on the page.

Include this html code inside your form tag:

<!-- display the script as an image --> 
<img src="advanced_captcha_script.php" /> 
<!-- an input box to input the captcha text -->  
<input name="captcha_input" id="captcha_input" />

The Script

<?php
session_start(); //MUST START SESSION 
$string_length = 6; //NUMBER OF CHARS TO DISPLAY 
$large_letters = array('m','w');
$rand_string = ''; 
 
for ($i=0; $i<$string_length; $i++) { 
  //PICK A RANDOM LOWERCASE LETTER USING ASCII CODE 
  $rand_string .= chr(rand(97,122)); 
}
 
//IMAGE VARIABLES 
$width = 100; 
$height = 36; 
 
//INIT IMAGE 
$img = imagecreatetruecolor($width, $height); 
 
//ALLOCATE COLORS 
$black = imagecolorallocate($img, 0, 0, 0); 
$gray = imagecolorallocate($img, 110, 110, 110); 
$medgray = imagecolorallocate($img, 180, 180, 180); 
$lightgray = imagecolorallocate($img, 220, 220, 220); 
//FILL BACKGROUND
imagefilledrectangle($img, 0, 0, $width, $height, $lightgray); 
 
//ADD NOISE - DRAW background squares
$square_count = 6;
for ($i = 0; $i < 10; $i++) {
  $cx = (int)rand(0, $width/2);
  $cy = (int)rand(0, $height);
  $h  = $cy + (int)rand(0, $height/5);
  $w  = $cx + (int)rand($width/3, $width);
  imagefilledrectangle($img, $cx, $cy, $w, $h, $medgray); 
}
 
//ADD NOISE - DRAW ELLIPSES
$ellipse_count = 5;
for ($i = 0; $i < $ellipse_count; $i++) {
  $cx = (int)rand(-1*($width/2), $width + ($width/2));
  $cy = (int)rand(-1*($height/2), $height + ($height/2));
  $h  = (int)rand($height/2, 2*$height);
  $w  = (int)rand($width/2, 2*$width);
  imageellipse($img, $cx, $cy, $w, $h, $gray);
}
 
//REPLACE THIS WITH THE FONT YOU UPLOAD 
$font = 'Tuffy.ttf'; 
$font_size = 18; 
 
//CALC APPROX LOCATION - CUSTOMIZED FOR ABOVE FONT 
$y_value = ($height/2) + ($font_size/2); 
$x_value = 0;
 
//DRAW STRING USING TRUE TYPE FUNCTION 
 
for ($i = 0; $i < $string_length; $i++) {
  $chr = substr($rand_string, $i, 1);
  $x_value += 3 * ($font_size/5); 
  imagettftext($img, $font_size, 0, $x_value, $y_value, $black, $font, $chr); 
  //check to see if larger than normal letters, if so add more horiz space
  if (in_array($chr, $large_letters)) {
    $x_value += 4;
  }
}
 
$_SESSION['encoded_captcha'] = md5($rand_string . 'my_secret_key'); 
 
//OUTPUT IMAGE HEADER AND SEND TO BROWSER 
header("Content-Type: image/png"); 
imagepng($img); 
?>

Here’s an example of what the captcha looks like (refresh the page to generate a new captcha):

Script Notes

We are using a font called “Tuffy.ttf” that is in the public domain in this script. You will need to download this font and upload to the same directory as the captcha script. You can download this font from the homepage of its creator or directly from my site.

Checking The Result

After the user has submitted the form, we still have to validate their captcha text entry. Without validation, our captcha security is useless. The general flow of things after the form has been submitted is:

  1. Compare the user entry to the captcha text
  2. If they are the same, enter the user’s content into your database
  3. If they are different, display an error message to the user.

If you examine the PHP script above you will notice that we are storing the generated captcha as a session variable concatenated with a secret key. If we use the PHP function session_start() on the next page after the form has been submitted, we will be able to access that stored session variable. We do not store it as plain text, or else a spam bot might be able to access the stored text in the session variable and then type the correct captcha text in the input box, bypassing our security. Instead, we store it a an md5() hash, which is a one-way encryption method. All md5() encrypted strings by their nature cannot be decrypted, so to validate the user entry we need to md5() encrypt the user’s input, concatenate in the secret key and compare it to the already encrypted session variable. Below is some PHP code that shows how we could validate the captcha:

<?php
session_start(); 
$user_content=trim($_POST['user_content']); 
$user_captcha_input=trim($_POST['user_captcha_input']); 
if (isset($_SESSION['encoded_captcha'])) { 
  if ($_SESSION['encoded_captcha'] == md5($user_captcha_input . 'my_secret_key')) { 
    //..THE USER IS NOT A BOT, STORE THEIR INPUT
  } 
  else { 
    //THE USER ENTERED THE WRONG CAPTCHA, 
    //DISPLAY AN ERROR MESSAGE AND 
    //DO NOT STORE THEIR INPUT
  } 
} 
?>

Comments

  1. Michael on 10 Dec 2008 at 9:43 pm

    I’m trying to use your script. Everything works fine but it submits the form whether the code is correctly input or even if it is left empty. Once the submit button is pressed, the user is redirected to formresults.php page where I added the “checking the result code to” at the top but apparently I’m doing something wrong. Any help would be greatly appreciated.

    Pages are:

    http://www.soundwaveslakeland.com/captcha.html (form)
    http://www.soundwaveslakeland.com/captcha.php (captcha script)
    http://www.soundwaveslakeland.com/ProcessForm.php (Form script)
    http://www.soundwaveslakeland.com/formresults.php (thank you page and summary of submitted content.)

    Tnanks, Michael

  2. Elliott Brueggeman on 10 Dec 2008 at 11:10 pm

    The form being submitted is expected – the captcha does not prevent this from happening. What you need to do is validate the captcha by performing the hash comparison as shown in code box two. For background on why hashes work, try searching Wikipedia for “md5″ which is PHP’s best hashing alogrithm.

  3. Burt on 27 Apr 2009 at 4:47 am

    How do I implement the validation code into the page?
    Thanks for a great script!

  4. Alok Mishra on 05 May 2009 at 1:17 am

    While implementing the captcha i found the following error from server after submission of the form :

    Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at /home/sitar/public_html/SendQuerys.php:2) in /home/sitar/public_html/SendQuerys.php on line 3
    You entered the wrong captcha image details.

  5. Brenda on 14 Aug 2009 at 12:50 pm

    Hi, love the script, as it is one I can actually use on html pages without having to use a bunch of code I can’t even figure out. However, try as I may, I flat can’t get it to move past the initial check onto the rest of my processing script. You don’t actually have an example of if true/false. Also, wouldn’t you need to also include a “require once” statement so your end processing form knows how-where to check your secret key? Sorry, I get a headache just thinking about scripts, much less understand all the code.

    Any help is most appreciated,
    Brenda

  6. web development company on 04 Feb 2010 at 12:01 am

    Seems to be a good content here. . . Yes, Captchas are images that are used to tell the difference between a person and computer but i don’t know how to create i using PHP. now i will try to use it in my web pages.

  7. Himansu on 19 May 2010 at 6:52 am

    I am using captcha in my form. But I want that if i don’t like to write like rather than i want to write like then how can i write that.

    img.php —->File which converts image to captcha image

    Please help me!
    Thanks

  8. Rud on 31 May 2010 at 3:44 am

    It’s very helpful.

    thanks

  9. amit on 29 Jun 2010 at 6:34 am

    hello i m amit
    can anyone tell me we can create multiple captcha image on same page?

    plz reply me…

    thanks in advance

Leave a Reply - Registration Not Necessary