Making a Captcha Verification Image

This is a short tutorial on adding a captcha verification image to a web form. PHP 4 or higher and the GD Image Library (comes bundled with newer PHP versions) are required.

Making a Captcha image is a lot simpler than you might think. It involves two main steps: generating a random string and making an image of that string.

Let's start with generating the string. This is the first part of captcha.php

<?php
session_start();

//$string will hold our generated random string
$string = "";

//List of characters that are unique (ie. no "1" and "I")
//This changes based on the font you use
$chars = "2345789ABcdEfGhJkmNpQrstVwxy";

//Choose 5 random characters from the list and 
//add to our string.
for($i=0;$i<5;$i++)
{
  $string .= $chars{rand(0,strlen($chars)-1)};
}

//Store our string in a session variable
$_SESSION['captcha'] = $string;

Now let's generate the image of this string, which is a little more complicated. This is part 2 of the captcha.php file.

//Set the output as a PNG image
header("Content-type: image/png");

//Tell browser to not store captcha in cache
header ("Cache-Control: no-cache, must-revalidate");
header ("Pragma: no-cache");

// create a new image canvas 160x60 px
$iwidth = 160;
$iheight = 60;
$image = imagecreate($iwidth, $iheight);

//Create colors (RGB values)
//Background color - light gray
$bg_color = imagecolorallocate($image, 230, 230, 230);
//Noise color for dots - green
$noise_color1 = imagecolorallocate($image, 40, 120, 80);
//Noise color for lines - light green
$noise_color2 = imagecolorallocate($image, 50, 180, 120);
//Text color - dark green
$text_color = imagecolorallocate($image, 20, 100, 40);

//Add 500 random dots to the image
//Lower this number if it's too hard to read
for( $i=0; $i<500; $i++ ) {
   //Create ellipses with 1px width and height
   imagefilledellipse($image, mt_rand(0,$iwidth), 
     mt_rand(0,$iheight), 1, 1, $noise_color1);
}

//Add 30 random lines to the image
//Lower this number if it's too hard to read
for( $i=0; $i<30; $i++ ) {
   //Make line with two random end points
   imageline($image, mt_rand(0,$iwidth), 
     mt_rand(0,$iheight), mt_rand(0,$iwidth), 
     mt_rand(0,$iheight), $noise_color2);
}

//Choose font file (download link after code block)
//I picked this font because it's easy to read
$font = "annifont.ttf";

//Choose font size
$fsize = 26;

//Set angle of font (just dealing with horizontal text for now)
$fangle = 0;

/*Useful function for getting dimensions of text
Returns:
array(
  0=>bottom left x position,
  1=>bottom left y position,
  2=>bottom right x position,
  3=>bottom right y position,
  4=>top right x position,
  5=>top right y position,
  6=>top left x position,
  7=>top left y position
)
*/
$dims = imagettfbbox ( $fsize, $fangle, $font, $string );

//Height is same as -1 times top_right_y 
$fheight = -1*$dims[5];
//Width is same as bottom_right_x
$fwidth = $dims[2];

//Get starting x,y position so text is centered
$fy = ($iheight-$fheight)/2+$fheight;
$fx = ($iwidth - $fwidth)/2;

//Now the magic function.  Adds the text to our image
//Using all the variables we created
imagettftext($image, $fsize, $fangle, $fx, $fy, 
  $text_color, $font , $string);

//generate a png image and output to screen
imagepng($image);

// destroy image resources
imagedestroy($image);
?>

Here a link to the font file: http://www.urbanfonts.com/fonts/Annifont.htm. Now you should be able to test your captcha image. Here's a demo of what it should look like: http://jeremydorn.com/demos/captcha.php

Now we add it to our form. This part is easy.

<img src='captcha.php' /><br />
Enter the text above: 
<input type='text' name='captcha' />

Finally, we check to see if they enter the right code. This next part goes in your validation script.

if(isset($_SESSION['captcha']) &&
$_REQUEST['captcha']==$_SESSION['captcha'])  {
  //correct code
}
else {
  //incorrect code
}

To see a sample form, go to http://jeremydorn.com/demos/captcha_form.php.

0 comments: