Form validation with Captcha image

In this tutorial I will show you how to create a captcha image to protect your form submissions.

Nowadays the spammers make more and more trouble for site administrators as they submit spams to forums, guestbooks, and registration forms and so on. To protect ourselves against spam robots it’s a good solution to extend our forms with a Captcha image. This image contains a security code which is only readable for humans and not for robots.

 

In this tutorial I will show you how you can generate such images on the fly with PHP and how to integrate it into your own form. First of all we need to split the task into 2 parts.

 

  • We need a PHP code which generates an image with a random code
  • We need a form where we check security code during processing.

 

Let’s begin with the image generation. If you think about it a bit we have to fulfill the following requirements:

 

  • Randomly generated code.
  • Randomly generated background image with some noise.
  • Randomly positioned characters.

 

So first create a background image. You can create it using the imagecreate function and pass the width and height as parameter.  It is quite simple.

 

<?php
$width  
120;
$height =  40;

$image = @imagecreate($width$height) or die('Cannot initialize GD!');
?>

 

Afterwards we add some criss-cross lines to the background. If you increase the number of execution the background will be more complex. For this task we can use imageline function which draws a line from point Ax,Ay to point Bx,By with a color C. To make it always different we generated all coordinates with mt_rand functions. The color is created with the imagecolorallocate function. The code part looks like this:

 

<?php
for( $i=0$i<10$i++ ) {
   
imageline($image
         
mt_rand(0,$width), mt_rand(0,$height), 
         
mt_rand(0,$width), mt_rand(0,$height), 
         
imagecolorallocate($imagemt_rand(150,255), 
                                    
mt_rand(150,255), 
                                    
mt_rand(150,255)));
}
?>

 

Now it’s time to add a random security code to the image.  To do this we first create a variable which contains all available characters. Later we will select a character one by one from this string randomly as follows:

 

<?php
$baseList 

'0123456789abcdfghjkmnpqrstvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
for( 
$i=0$x=0$i<$length$i++ ) {
   
$actChar substr($baseListrand(0strlen($baseList)-1), 1);
   
$x += 10 mt_rand(0,10);
   
imagechar($imagemt_rand(3,5), $xmt_rand(5,20), $actChar
      
imagecolorallocate($imagemt_rand(0,155), mt_rand(0,155), mt_rand(0,155)));
   
$code .= strtolower($actChar);
}
?>

 

If we have a character we need to add it to the image. For this we use imagechar function. However during the positioning we again use some randomizing just to make our Captcha image more complex.

 

At least we store the selected character in a separate variable which will be used later. The PHP code for this task looks like this:

 

<?php
header
('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image);

$_SESSION['securityCode'] = $code;
?>

 

Finally we create the image and send it to the browser to display it.

 

The very last step is to store the collected characters, our code in a session variable. Later during the form processing this variable will be used.

 

You can find the complete Captcha image generator code on the last page of this tutorial.

 

Form processing

 

The next big task is to create a form using the image we just generated and process the visitor inputs. As you may remember we have stored the security code in a session variable so we need to start a session first. As next step we can check if the form was submitted or not. If not then we can display a form. Here you can create as complex form as you want. The only important thing is that you need to add an input text field for the security code and of course you need to display the Captcha image. This last step is very simple; just use our first PHP – which generates the image - code as image source.  The form should look like this:

 

      <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" >
        <table width="400">
          <tr>
            <td>Security code: 
               <input class="text" name="secCode" type="text" size="10" />
            </td>
            <td>
               <img src="securityCode.php" alt="security code" border="1" />
            </td>
          </tr>
          <tr>
            <td colspan="2" align="center"><br/>
               <input class="text" type="submit" name="submitBtn" value="Send" />
            </td>
          </tr>
        </table>  
      </form>

 

Now back to the form processing part of the script. First we need to check the existence of the security code and if it was submitted then we convert it to lowercase to make it case insensitive. If you want to make a case sensitive Captcha solution then you also need to modify the image generation script and remove the strtolower function.

 

It’s time to check if the security code we have saved in the session is the same as the security code typed by the visitor.  If it is valid then we clean the session variable and set a result variable. This result variable will show us if we need to display the form again or not. You need to call your own business logic inside the valid case.

 

The complete check procedure is the following:

 

<?php
   
if (isset($_POST['submitBtn'])){
      
$secCode = isset($_POST['secCode']) ? strtolower($_POST['secCode']) : "";
      if (
$secCode == $_SESSION['securityCode']) {
         echo 
"<p>The result code was valid!<br/></p>";
         unset(
$_SESSION['securityCode']);
         
$result true;
      }
      else {
         echo 
"<p>Sorry the security code is invalid! Please try it again!</p>";
         
$result false;
      }
   }
?> 

 

That’s all, we are ready!

 

Complete code

 

The image generator script:

 

<?php
session_start
();

$width  120;
$height =  40;
$length =   5;

$baseList '0123456789abcdfghjkmnpqrstvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

$code    "";
$counter 0;

$image = @imagecreate($width$height) or die('Cannot initialize GD!');

for( 
$i=0$i<10$i++ ) {
   
imageline($image
         
mt_rand(0,$width), mt_rand(0,$height), 
         
mt_rand(0,$width), mt_rand(0,$height), 
         
imagecolorallocate($imagemt_rand(150,255), 
                                    
mt_rand(150,255), 
                                    
mt_rand(150,255)));
}

for( 
$i=0$x=0$i<$length$i++ ) {
   
$actChar substr($baseListrand(0strlen($baseList)-1), 1);
   
$x += 10 mt_rand(0,10);
   
imagechar($imagemt_rand(3,5), $xmt_rand(5,20), $actChar
      
imagecolorallocate($imagemt_rand(0,155), mt_rand(0,155), mt_rand(0,155)));
   
$code .= strtolower($actChar);
}
   
header('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image);

$_SESSION['securityCode'] = $code;

?>

 

The form:

 

<?php session_start(); ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "DTD/xhtml1-transitional.dtd">
<html>
<head>
   <title>Captcha demo</title>
</head>
<body>
<?php
   
if (isset($_POST['submitBtn'])){
      
$secCode = isset($_POST['secCode']) ? strtolower($_POST['secCode']) : "";
      if (
$secCode == $_SESSION['securityCode']) {
         echo 
"<p>The result code was valid!<br/></p>";
         unset(
$_SESSION['securityCode']);
         
$result true;
      }
      else {
         echo 
"<p>Sorry the security code is invalid! Please try it again!</p>";
         
$result false;
      }
   }
   
   if ((!isset(
$_POST['submitBtn'])) || (!$result)){
?>      
      <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" >
        <table width="400">
          <tr>
            <td>Security code: 
               <input class="text" name="secCode" type="text" size="10" />
            </td>
            <td>
               <img src="securityCode.php" alt="security code" border="1" />
            </td>
          </tr>
          <tr>
            <td colspan="2" align="center"><br/>
               <input class="text" type="submit" name="submitBtn" value="Send" />
            </td>
          </tr>
        </table>  
      </form>
<?php
   

?>      
</body>