You likely have encountered CAPTCHA on a number of websites you visit. It is that small image with a verification code that you type into a box before submitting something. CAPTCHA is a very simple and common protection that helps prevent spam and the automatic submission of an operation by some kind of program or robot. CAPTCHA protection is used on web site forms and works by generating a random string, writing it to an image, then storing the string inside of a session. Then, the site checks the CAPTCHA when the form is submitted. In this article, you will learn how to make your own simple CAPTCHA image using PHP. You will create the CAPTCHA image step by step.
The core of the demo application is a PHP class capable of generating random text and an image that will contain the text (the class is encapsulated in the GeneratedCaptcha.php script). This image will be your CAPTCHA. Take the following steps to create your CAPTCHA image.
1. Generate a random text. You store the characters allowed in the random text in an array, one character per position. Next, you use the mt_rand function to generate random positions in your array. Then, you concatenate the corresponding characters into a string and provide the length of the string as an argument of the GenerateCaptchaText function, listed below:
function GenerateCaptchaText($c) {   
   $captcha = '';
   $supportedCharacter = array('1','2','3',
                               '4','5','6',
                               '7','8','9',
                               '0','a','b',
                               'c','d','e',
                               'f','g','h',
                               'i','j','k',
                               'l','m','n',
                               'o','p','q',
                               'r','s','t',
                               'u','v','w',
                               'x','y','z',
                               '!','$','%');
           
   for ($i = 1; $i <= $c; $i++) {
      $position = mt_rand(0,sizeof($supportedCharacter) - 1); 
      $captcha .= $supportedCharacter[$position];         
      }
                           
   return $captcha;
   }
2. Generate the image containing the random text. The main function of your class, GenerateCaptcha, accomplishes this task.
  1. Start by calling the GenerateCaptchaText function to obtain the random text that will be included in the picture:
    //generate the captcha text
    $captcha = $this->GenerateCaptchaText($c);
    
  2. Create the CAPTCHA image using the $w and $h width and height arguments set in the default CAPTCHA configuration section. To do that, you use the imagecreate function (see the PHP manual to learn more about this function):
    //create the image
    $image = @imagecreate($w, $h) 
    or die('Cannot create main image!');
    
  3. Set the background and the text color of the CAPTCHA image using the imagecolorallocate PHP function:
    // set the captcha image  -  text will be white rendered on black
    $bg_color = imagecolorallocate($image, 255, 255, 255);
     //we don't random here to be sure that the text is visible            
    $captcha_color = imagecolorallocate($image, 0, 0, 0);
      //we don't random here to be sure that the text is visible
    
  4. The resulting CAPTCHA image will include some generated lines, dots, and rectangles. But before that, you generate random colors for it, using the imagecolorallocate function:
    //backstage colors  -  lines, dots and rectangles             
    $line_color = imagecolorallocate($image, mt_rand(0,255), 0, 255);
    $dots_color = imagecolorallocate($image, mt_rand(0,255),255,mt_rand(0,255));   
    $rect_color = imagecolorallocate($image, 0,mt_rand(50,127),50);   
    
  5. Add some "security" marks. For this, you will draw with random colors some dots, rectangles, and lines in the background of the CAPTCHA to make sure that a robot application can not identify and extract the CAPTCHA text (in addition, the text is rendered with different sizes and fonts, and at different coordinates). To generate random dots for the background of the CAPTCHA image, you use the imagefilledellipse PHP function with random x and y coordinates for the center, width, and height. The x coordinate of the center will be a number between 0 and the width of the ellipse; the y coordinate of the center is a number between 0 and the height of the ellipse. The width and height of the ellipse are random numbers between 0 and 3, for obtaining ellipses with dot aspect.
    // generate random dots
    for( $i=0; $i<($w * $h); $i++ ) {
       imagefilledellipse($image, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,3), 
          mt_rand(0,3), $dots_color);
       }
    
    To generate random lines using the imageline PHP function, randomly generate the lengths and the coordinates of the lines as in the below code:
    // generate random lines
    for( $i=0; $i<($w + $h)/3; $i++ ) {
       imageline($image, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), 
          mt_rand(0,$h), $line_color);
       }
    
    To generate random rectangles using the imagerectangle PHP function, randomly generate the sizes of the rectangles as in the below code:
    // generate random rectangles
    for( $i=0; $i<($w + $h)/3; $i++ ) {
    imagerectangle($image, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), 
          mt_rand(0,$h), $rect_color);
         }
    
  6. Create a bounding box of text using TrueType fonts. To do that, you can use the imagettfbbox PHP function:
    // create bounding box in pixels for a TrueType text
    $tb = imagettfbbox($h * 0.80, 0, $f, $captcha) 
    or die('Cannot create bounding box in pixels for this TrueType text!');
    
  7. The most important step is writing the generated text on top of the generated image using the TrueType font. For this, you need the imagettftext PHP function.
    $urcX = ($w - $tb[4])/2; //tb[4] = upper right corner, X position
    $urcY = ($h - $tb[5])/2; //tb[5] = upper right corner, Y position
    //write the given text  into the image using TrueType font
    imagettftext($image, mt_rand($h * 0.50,$h * 0.80), 0, $urcX, $urcY, $captcha_color, $f , $captcha) 
    or die('Cannot write the given text  into the image using TrueType font!');
    
  8. For a nice design, you can go further and apply image filters. For example, you can apply IMG_FILTER_NEGATE and IMG_FILTER_SMOOTH PHP predefined image filters using the imagefilter PHP function:
    //apply two image filters    
    imagefilter($image,IMG_FILTER_NEGATE);
    imagefilter($image,IMG_FILTER_SMOOTH,1);
    
  9. Output the CAPTCHA image on the browser:
    // output captcha image to browser 
    header('Content-Type: image/jpeg');
    imagejpeg($image);
          
    imagedestroy($image);   
    
  10. The last step is to store the CAPTCHA text on the session:
    // storing on session the captcha text
    $_SESSION['captchaCheck'] = $captcha; 
    

Putting It All Together

The sections to follow explain how to put all the above steps together to obtain the complete GenerateCaptcha class (see Listing 1).
The line that glues together the client page and the CAPTCHA script is the line that instantiate the GenerateCaptcha class:
//create captcha
$generate_captcha = new GenerateCaptcha($w, $h, $use_font, $chs);
Author Note: The arguments passed to the GenerateCaptcha function represent the CAPTCHA's custom parameters:
  • the width of the CAPTCHA image (width=300)
  • the height of the CAPTCHA image (height=150)
  • number of characters rendered in the image (chs=3)
  • font type (font=AdvertRegular)—You use only two True Type fonts in this example, as you can see in the {/fonts} folder.
Those parameters are set in the test_custom.php script using the following line of code:
<img src="GenerateCaptcha.php?width=300&height=150&chs=3&font=AdvertRegular"/>
The customizable parameters are passed to the GeneratedCaptcha.php script, which processes them with the code below:
//start a new session
session_start();

//set the default captcha configuration
$w = 150;       //the width of the captcha image
$h = 50;        //the height of the captcha image
$chs = 5;        //number of characters rendered in image
$font = "AardvarkCafe";//font type

//get the custom configuration
if(isset($_GET['width'])) { $w = $_GET['width']; }
if(isset($_GET['height'])) { $h = $_GET['height']; }
if(isset($_GET['chs'])) { $chs = $_GET['chs']; }
if(isset($_GET['font'])) { $font = $_GET['font']; }

//set the font path
$use_font = "./fonts/".$font.".ttf";  
Now that you have finished your CAPTCHA script, it is time to see how it works. For this, you can write a simple PHP test using simple forms like test_default.php (see Listing 2) and test_custom.php (see Listing 3).
Notice how you call the GenerateCaptcha.php script in the img HTML element. To display the CAPTCHA image, you use the common img HTML element with the specification that the image is generated dynamically (using the GenerateCaptcha.php described previously).
The final step is to check if the generated CAPTCHA text stored on the session is equal to the text provided by the user in the form:
if($_SESSION['captchaCheck'] == $_POST['providedCaptcha']  && !empty($_SESSION['captchaCheck']))
Here is the register.php script:
<?php 
session_start();

if(isset($_POST['submit'])) {
if($_SESSION['captchaCheck'] == $_POST['providedCaptcha']  && !empty($_SESSION['captchaCheck'])){
     
     // TODO
     echo $_POST['user']." was successfully register with e-mail 
     ".$_POST['email']."!";
     unset($_SESSION['captchaCheck']);
      } else {
         //TODO
         echo "The inserted text (".$_POST['providedCaptcha'].") does   
         not match the rendered one (".$_SESSION['captchaCheck'].")!";
   }
} 
?>
In both examples (test_default.php and test_custom.php), after the user submits the form, a message will display. Figure 1 shows the output of the test_default.php scripts.



Click here for larger image

After the user (Octavia, in this case) submits text that proves valid, the following text will appear:
Octavia was successfully registered with e-mail octavia_anghell@yahoo.com!
Figure 2 shows the output of the test_default.php script when the CAPTCHA text does not match the provided text.



Click here for larger image

If the user inserts text that does not match the CAPTCHA, the text below will appear:
The inserted text (5j5k22) does not match the rendered one ()!
Figure 3 shows the output of the test_custom.php script.



Click here for larger image

After the user submits valid text, the following message will appear:
Octavia was successfully registered with e-mail octavia_anghell@yahoo.com!
If the inserted text does not match the CAPTCHA, the text below will appear:
The inserted text (h!w) does not match the rendered one (wim)!
Figure 4 shows the output of the test_custom.php script when the CAPTCHA text does not match the provided text.



Click here for larger image

What Have You Learned?

In this article, you got step-by-step instructions for creating your own CAPTCHA using PHP. You learned how to customize the CAPTCHA parameters to your liking for better design and protection of your web site.
Code Download
About the Author
Octavia Andreea Anghel is a senior PHP developer currently working as a primary trainer for programming teams that participate at national and international software-development contests. She consults on developing educational projects at a national level. She is a coauthor of the book "XML TechnologiesXML in Java" (Albastra, ISBN 978-973-650-210-1), for which she wrote the XML portions. In addition to PHP and XML, she's interested in software architecture, web services, UML, and high-performance unit tests. to e-mail her.