How to Generate an Image Captcha

tom Tom, 19th February 2008

Everyone hates spammers, how they sleep at night I don't know... Maybe they are so rich they can afford to buy those special space age mattresses that mold to fit your shape, or machines that imitate the sound of the ocean! (OK I got that from a film). But one tried and tested way of reducing your websites chance of being the victim of spam is to protect all your forms with an image captcha. The big sites like Yahoo have been using image captcha's for years, but the idea of generating an image simply by writing code may be a little daunting for some. It was for me, until I actually sat down and gave it a go... Surprisingly it's very easy, and I'll show you how to create a basic image captcha in this article. Everything I code is in PHP, so if you are looking for any other way of generating a captcha I'm afraid I can't help you, although I suspect the principles are pretty much the same. In summary the basic requirements for this to work are: a) You need to be able to use sessions b) You need to have the gd library installed in your version of PHP. You can check to see if it is enabled by using the phpinfo() function. I've found that most recent installations of PHP seem to have it setup by default, so you should be ok on both counts. In summary this is how it works: i) You generate a random code ii) You store this random code in the users session iii) You also generate an image using PHP and display a distorted version of this code in the image. iv) You ask the user to enter what they see in the captcha. v) On the form submission you check to see if they entered what you already have stored in the session. If the two codes match then you have a human, if they don't they you either have a very frustrated user or a bot, either way they get an error message and asked to try again. See I told you it was simple! All that's left for me to do it provide you with a little actual code to work on. The Code - verification.php This is the all important file that does all your work for you. It generates your code, saves it in the session and generates your image. <?PHP // Start the session for the user session_start(); // Generate the verification number and store in the session $verification_code = array(); // Create an image with 4 characters for($i=0; $i<4; $i++) { if(rand(0,1) == 1) { $verification_code[] = chr(rand(97,122)); // Choose any lowercase letter in the range a-z } else { $verification_code[] = chr(rand(49,57)); // Choose any number in the range 1-9 } } // Save the code in the session $_SESSION['verification'] = md5(implode("", $verification_code)); // Now we create the verification image itself // We have 4 different background images which we'll use to create the images // You can create these in the graphics program of your choice. // We then randomly select one of these images to use as the background for our image captcha $image = imagecreatefromjpeg("/path/to/background/images/background_".rand(1,4).".jpg"); $text_colour = imagecolorallocate($image, 255, 255, 255); // Add text to the verification image $x_offset = 16; foreach($verification_code as $chr) { imagettftext($image, (22+(rand(-4, 4))), rand(-20, 20), $x_offset, (31+(rand(-5, 5))), $text_colour, '/path/to/fonts/trebuc.ttf', $chr); $x_offset += 22; } // Make sure the page isn't cached and set the content type to image/jpeg header("Expires:Mon, 01 Jan 2002 05:00:00 GMT"); header("Last-Modified:".date("D, d M Y H:i:s")." GMT"); header("Cache-Control:no-store,no-cache,must-revalidate"); header("Cache-Control:post-check=0,pre-check=0",false); header("Pragma:no-cache"); header('Content-type:image/jpeg'); // Finally we can send our response back to the user and free any memory associated with image imagejpeg($image,null,100); imagedestroy($image); ?> Now to use your image captcha simply include it within an image tag within a form as follows. <form method="post"> <input type="text" class="text" name="verification" id="verification" /> <img src="verification.php" alt="please enter the text you see in this image" /> <input type="submit" name="submit_button" id="submit_button" /> </form> Now when you submit the form the last check is to make sure the code entered in the form is the same as the code saved in the session that appears in the image captcha. As we md5 hashed the value in the session we need to compare like for like. <?PHP $error = array(); if (md5($_POST['verification']) != $_SESSION['verification']) { $error[] = "Please re-enter the verification image. NB. All letters are capitals."; } ?> Troubleshooting The main gotchas I've found in the past were missing font files; you'll need to download the .ttf file for whichever font you choose to use. These are available on the Internet (or even on your computer most likely). Just remember to upload them to your server and provide the path to them when calling the imagettftext() function. If PHP can't find the font file you won't see the image at all. So there you have it, pretty simple really and a great bit of code to include in your web forms to help stop those pesky spam bots. You can see the code in action here.

More from our blog

18a win Netty 2024 award for Activibees.com

18a win Netty 2024 award for Activibees.com

29.02.24

We are delighted to announce that 18a has been recognised for its outstanding work in the "Web Design Agency of the Year - UK" category at… Read →

Generating an Effective Content Security Policy with your Laravel React App

Generating an Effective Content Security Policy with your Laravel React App

27.02.24

I recently had an interesting problem to solve. I'd built a brand new author website on a shiny installation of Laravel 10, utilising its out-of-the-box… Read →

If your WordPress website looks broken, it could be because of this.

If your WordPress website looks broken, it could be because of this.

15.02.24

WordPress is the incredibly popular blogging-come-full-website platform that powers over 835 million websites* in 2024. It's functionality is extended by plugins, and one such very… Read →