Tutorial: improving security with a PHP Captcha

by stark in Programming, Technology, Web Design

· 6 Comments

Although you might not know it by the name, a captcha is one of those little boxes you see, more and more lately, that ask you to type in a random code to verify that you are a human being and not a robot. There are many different varieties, but the basic idea is an image that is obscured slightly but readable by a human and used as a passcode for secure entry to a system or task. Something similar to this:

The user is asked to type in the string buried inside the image, and if it matches, they are given access to a specific resource, such as posting a comment or logging into a site.

The 7 step captcha breakdown

The basic idea behind adding a captcha to any website can be summarized by the following 7 steps:

  1. Generate some random text.
  2. Add that text to a cookie/session/database so you can retrieve it again from another page.
  3. Write the text onto an existing image.
  4. Display the image to the user wanting access to a resource.
  5. Provide a form, where the user enters the code and submits the form.
  6. Verify the code against the key you stored in step 2.
  7. If the codes match, then grant access.

In the next few sections, I’ll step through the code for a very basic example of a captcha script for your own website. At the end, you can download the example code and try it out for yourself.

Generating the key and storing it for verification

The first step in the process of building a working captcha system is to generate a string of random text. There are many ways to do this, so feel free to experiment, but one of the simplest methods is to take a value that is constantly changing and encrypt it, such as system time or date information. For the following we will use the functions microtime( ) and mktime( ) to create a totally random string, and then encrypt it using the md5( ) encryption tools built into PHP.

<?php

// Start the session so we can store our generated key inside it for later retrieval

session_start( );

// Set to whatever size you want, or randomize for more security

$captchaTextSize = 7;

do {

    // Generate a random string and encrypt it with md5

    $md5Hash = md5( microtime( ) * mktime( ) );

    // Remove any hard to distinguish characters from our hash

    preg_replace( ‘([1aeilou0])’, “”, $md5Hash );

} while( strlen( $md5Hash ) < $captchaTextSize );

// we need only 7 characters for this captcha

$key = substr( $md5Hash, 0, $captchaTextSize );

// Add the newly generated key to the session. Note, it is encrypted.

$_SESSION[‘key’] = md5( $key );

?>

The next step is to actually display the key on our captcha image and display it to the user on the screen.

Displaying the random text on the captcha image

Now that we have generated our captcha key and stored it in our session for later verification, we now need to display it. This is accomplished using the PHP GD image package.

<?php

// grab the base image from our pre-generated captcha image background

$captchaImage = imagecreatefrompng( “images/captcha.png” );

/*

Select a color for the text. Since our background is an aqua/greenish color, we choose a text color that will stand out, but not completely. A slightly darker green in our case.

*/ 

$textColor = imagecolorallocate( $captchaImage, 31, 118, 92 );

/*

Select a color for the random lines we want to draw on top of the image, in this case, we are going to use another shade of green/blue

*/

$lineColor = imagecolorallocate( $captchaImage, 15, 103, 103 );

?>

Now that we have colors selected, we want to randomly throw some lines onto the image, which will increase the difficulty for robotic parsing of our text.

<?php

// get the size parameters of our image

$imageInfo = getimagesize( “images/captcha.png” );

// decide how many lines you want to draw

$linesToDraw = 10;

// Add the lines randomly to the image

for( $i = 0; $i < $linesToDraw; $i++ )  {

         // generate random start spots and end spots

         $xStart = mt_rand( 0, $imageInfo[ 0 ] );

         $xEnd = mt_rand( 0, $imageInfo[ 0 ] );

         // Draw the line to the captcha

        imageline( $captchaImage, $xStart, 0, $xEnd, $imageInfo[1], $lineColor );

}

?>

Finally, we write our key onto the image, and display the image to the screen. We started initially with a pre-generated background image. This could easily be elaborated to include dozens of additional backgrounds, selected at random, or even more complex would be to generate the background yourself, inside the captcha script. The function we are using to write the text is imagettftext which takes a string path to a true type font and outputs the text using it. In this case, I am using BitStream Vera Sans Bold, which is an open source font available for both copying and redistribution. You could use almost any font you want, or even mix up the font randomly to make it even more difficult for robots to read your image.

<?php

/*

Draw our randomly generated string to our captcha using the given true type font. In this case, I am using BitStream Vera Sans Bold, but you could modify it to any other font you wanted to use.

*/

imagettftext( $captchaImage, 20, 0, 35, 35, $textColor, “fonts/VeraBd.ttf”, $key );

// Output the image to the browser, header settings prevent caching

header ( “Content-type: image/png” );

header(“Cache-Control: no-cache, must-revalidate”);
header(“Expires: Fri, 19 Jan 1994 05:00:00 GMT”);
header(“Pragma: no-cache”);

imagepng( $captchaImage );

?>

Now that we have our captcha generating package, the final step in the process is to actually build a form for interacting with the user. 

Setting up the captcha entry page

To verify correct entry of the captcha code, you need to setup a form which allows the user to see the captcha and has a text field for them to type in the text they see. You will also need a submit button to send the entered results for verification. This is fairly simple to do for any web developer, but here is just a quick and dirty example.

<img src=”captcha.php” border=”0″ />

<form name=”captcha-form” method=”POST” action=”captcha-verify.php”>

         <input type=”text” name=”code” width=”25″ />

         <input type=”submit” name=”submit” value=”submit” />

</form>

Now, assuming the above form has been sumitted, you could verify the results in a script similar to this.

<?php

session_start( ); // allows us to retrieve our key form the session

/*

First encrypt the key passed by the form, then compare it to the already encrypted key we have stored inside our session variable

*/

if( md5( $_POST[ ‘code’ ] ) != $_SESSION[ ‘key’ ] ) {

       echo “You ented the wrong code, please try again!”;

} else {

       echo “Success, you ented the correct code, rock and roll…”;

}

?>

Obviously, there is much more customization you can do to make both of these fit within your existing setup and themes, but hopefully you get the general idea with these examples. That’s all there is to it.

Final words

This tutorial covers the very basics of a captcha solution written in PHP but it is far from the most robust solution available. There are man improvements you can make, using this as a base, that will make things all the more difficult for spammers to break. For example:

  • Use words instead of a random string, or even combine two or more words to make a semi-readable word that is not a dictionary word. For example, make 2 files, one full of starts and one full of ends and choose one of each to make a word at random like potatoism or internetyte.
  • Rotate the text randomly, and play with the spacing between letters. You can also mess with case and coloring of each letter as well. Skies the limit, but remember, you don’t want the word to be so hard, even your human users can’t figure it out.
  • Change the text positioning on the screen. In our example, the text always appears at the same spot, but you could easily change that to mix it up randomly.

I hope this introduction to captcha building has been of some help. Anything we can do to stop the spammers in their tracks is a victory for users everywhere. Let me know what you think of this tutorial, and as always, any suggestions you might have to offer are most welcome. 

You can download the files used in this example and use them to play around with the Captcha yourself. If you get something to work, drop a comment and let us all take a look at your solution in action.

[tags]tutorial, php, captcha, security, spam blocking, robot blocking, verification, commenting, spamming[/tags]

Tags: , , , , , , , , , , ,

← Previous

Next →

6 Comments

  1. […] Original post by FuzzyOpinions.com and software by Elliott Back Posted 17 Feb, 2007 | Categories: Uncategorized  […]

  2. senthil says:

    Nice tutorial for creating captcha tool.. Nice work done…

  3. Alisa says:

    I downloaded the files and uploaded all the files to the server just to test it out. It didn’t seem to work properly. When I entered the right code, it still said I entered the code incorrectly. I already enable the cookies, and still couldn’t figure it out why it didn’t work. Please advise.

  4. chika says:

    Is there a need to chmod any file? I was able to set it up correctly on my localhost xampp for windows but could not get the image to appear when I transferred it online (LAMP server). Thanks -chika

  5. Gabby Conception says:

    Is there any requirements on this captcha? It works on some server and not on some. Thanks

  6. thoseguys says:

    I just switched servers/hosts and now my captcha images are gone? Does this only work with a certain version of php or something? I am totally confused!

Leave a Comment