Creating a PHP Captcha

Captchas are images that are meant to tell the difference between a person and a computer. They are often used as an anti-spam device when someone submits content to a public website. Because a computer has a very difficult time parsing the contents of an image, captcha’s are very effective.

Below is an easy to implement PHP captcha script and example implementation. Spammers have even developed software to read as captchas like this too, and I’ll mention some strategies to strengthen your catpcha later.

Requirements

To use this captcha script, you will need PHP enabled on your server with the Image (GD) extension enabled.

Setup

On the page where your users are submitting content, you want to display the captcha and an input box for the user to enter the text as seen in the captcha. To use the PHP script below to you need to include it as an image on the page you want it to display – save the script as something like “captcha_script.php” and use the following html to display it on the page.

Include this html code inside your form tag:

<!-- display the script as an image -->
<img src="captcha_script.php" />
<!-- an input box to input the captcha text -->
<input name="captcha_input" id="captcha_input" />

The Script

<?php
session_start(); //MUST START SESSION
$string_length=5; //NUMBER OF CHARS TO DISPLAY
$rand_string='';
for($i=0;$i<$string_length;$i++)
{
  //PICK A RANDOM UPPERCASE LETTER USING ASCII CODE
  $rand_string.=chr(rand(65,90));
}//IMAGE VARIABLES
$width=100;
$height=36;
//INIT IMAGE
$img=imagecreatetruecolor($width, $height);
//ALLOCATE COLORS
$black=imagecolorallocate($img, 0, 0, 0);
$gray=imagecolorallocate($img, 200, 200, 200);
imagefilledrectangle($img, 0, 0, $width, $height, $gray);
//REPLACE THIS WITH THE FONT YOU UPLOAD
$font='BELLB.TTF';
$font_size=16;
//CALC APPROX LOCATION FOR TEXT
$y_value=($height/2)+($font_size/2);
$x_value=($width-($string_length*$font_size))/2;
//DRAW STRING USING TRUE TYPE FUNCTION
imagettftext($img, $font_size, 0, $x_value,
    $y_value, $black, $font, $rand_string);
$_SESSION['encoded_captcha']=md5($rand_string);
//OUTPUT IMAGE HEADER AND SEND TO BROWSER
header("Content-Type: image/png");
imagepng($img);
?>

Here’s an example of what the captcha looks like (refresh the page to generate a new captcha):

Script Notes

Instead of using a default font of PHP’s image extension, we are using a true-type font that is available to our script. You need to change this to a font that you upload to your site. To do this, pick a font that you like and find the font file on your computer. In Windows, fonts are usually located in the C:\WINDOWS\Fonts folder. Find a .TTF font file, which is the True Type extension and then upload that file to the same directory as the captcha image script. Then, change the code in the script from $font=”BELLB.TTF”; to $font=”MYUPLOADEDFONT.TTF” to make this font work with your captcha.

Checking The Result

After the user has submitted the form, we still have to validate their captcha text entry. Without validation, our captcha security is useless. The general flow of things after the form has been submitted is:

  1. Compare the user entry to the captcha text
  2. If they are the same, enter the user’s content into your database
  3. If they are different, display an error message to the user.

If you examine the PHP script above you will notice that we are storing the generated captcha as a session variable. If we use the PHP function session_start() on the next page after the form has been submitted, we will be able to access that stored session variable. We do not store it as plain text, or else a spam bot might be able to access the stored text in the session variable and then type the correct captcha text in the input box, bypassing our security. Instead, we store it a an md5() hash, which is a one-way encryption method. All md5() encrypted strings by their nature cannot be decrypted, so to validate the user entry we need to md5() encrypt the user’s input and compare it to the already encrypted session variable. Below is some PHP code that shows how we could validate the captcha:

<?php
session_start();
$user_content=trim($_POST['user_content']);
$user_captcha_input=trim($_POST['user_captcha_input']);
if(isset($_SESSION['encoded_captcha']))
{
  if($_SESSION['encoded_captcha'] == md5($user_captcha_input))
  {
  //..THE USER IS TRUSTED, STORE THEIR CONTENT
  }
  else
  {
  //THE USER ENTERED THE WRONG CAPTCHA
  //DISPLAY AN ERROR MESSAGE
  }
}
?>

Additional Modifications

This captcha is not immune to a computer script that could parse and read the image, so we could make it a little more secure. One optimization is to make it harder for a bot to parse is to add noise and lines to the background. This makes it harder for bots to perform segmentation on the image, which is the process of splitting up the image into individual characters.