How to make your very own CAPTCHA
Posted in Development by Alex | Tags: captcha, code, script, tutorialCAPTCHA – a familiar term to some of us but also a weird word for others, nonetheless CAPTCHA is one of those thing everybody comes in contact somehow. Like the name tells it CAPTCHA is a acronym for Completely Automated Public Turing test to tell Computers and Humans Apart. Basically it`s whole purpose is to tell if you are a human or a bot.
![]()
The system is a security feature first implemented by Yahoo, and soon spreaded on a big number of systems to improve security. The CAPTCHA is a representative image containing squiggly words that asks the user to type the word inside a form. A thing that a machine cannot possibly do.
How can CAPTCHA protect you?
There is a number of ways that it can protect you. Here are some of the places that users tend to come across squiggly images:
- Protecting a web registration form from automated registrations
- Preventing automatic posting of advertising comments by robots on blogs or other similar applications.
- Protection of voting systems from robots that try to fraud the results.
- Preventing spam on contact forms.
At the moment, there are a vast variety of free or commercial solutions to a CAPTCHA system, but the down side is that because of the variety of the forms, the easier is for the bots to adapt. Sometimes the images are to similar, the letters are to understandable and the list can go on. We will make a simple system, that makes robot adaptation as hard as possible, so your system is protected at all times.
Server requirements
- PHP 4.1.0 or recent (PHP 5.x.x for blur)
- FreeType library
- GD 2.0.1 or recent
In the config file, we will define the paths to the image and font used by the CAPTCHA system, you can specify your own images and font. Note: all of the fonts used in this tutorial are free fonts.
Fonts used in this tutorial
Images used in this tutorial
Let`s build the form
First step, creating the config file
We will create a config file (config.php) in which we will define the parameters of the code. The generated code must be available to the script that renders the user`s input of the form.
You can use a variety of systems like temp files, sessions or databases. In this tutorial we will use sessions, because they are the easiest to implement.
Thus we will first define the variable name in witch we will keep the code:
$sessionVar = 'myCaptcha';
Next step is to define the allowed characters
$allowedChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789';
Note that we skiped the number 0 (zero) to avoid confusion between zero and the letter “O” (capital o).
Now, we will make the lenght random, thus creating a more secure form.
$minCodeLength = 4; $maxCodeLength = 6;
We know that a same letter size captcha is cracked more easily, so in the next markup we will randomize the letter height. The size will be measured in pixels.
$minFontSize = 24; $maxFontSize = 32;
Another thing that influences CAPTCHA recognition for robots is the linear placement of the letters, so we will move them around the middle line.
$maxVerticalDisplacement = 15;
Now, we will rotate the letters a bit.
$maxRotationLeft = 15; $maxRotationRight = 15;
Now, we will be adjusting the padding of the letters
$textPadding = 5;
Ok, now we will change the colours of the background
$bgColor = array(255, 255, 255);
Next, we will define an array on the allowed color hex tags for the letters
$textColor = array( '200, 0, 0', '30, 200, 0', '150, 0, 200', '150, 150, 0', '100, 100, 100', 'ff0099', '99ff00' );
Different fonts for each letter? Never been so easy. Here is how you can do it. Keep in mind that you need the FreeType library fr the GD to work. You can find free fonts on the DaFont website.
$fontsFolder = 'my_fonts/'; $fontFiles = array( 'elektra.ttf', 'episode1.ttf', 'lcd2bold.ttf', 'optimusprinceps.ttf', 'sams_town.ttf', 'steinerlight.ttf', 'turn_table.ttf' );
Now let`s set up the background images
$backgroundsFolder = 'my_backgrounds/'; $backgrounds = array( 'bg_1.png', 'bg_2.png', 'bg_3.png', 'bg_4.png' );
Don’t forget to replace the paths and names of the fonts and images with your own.
Enough with the config, lets create something. Create a new php file, let`s say show_code.php that we will call like an ordinary image call.
<img src="show_code.php" alt="myCaptcha" />
Next, include the starting command and the config file:
session_start(); include_once('config.php'); $_SESSION[$sessionVar] = '';
Next, we will need a function that will return the occupied space of a letter:
function getCharSize($fontFile, $char, $size, $angle=0){ if( is_file($fontFile) && strlen($char) == 1 && $size > 0){ $corners = @imagettfbbox( $size, $angle, $fontFile, $char ); $left = ($corners[0]>$corners[6])?$corners[6]:$corners[0]; $right = ($corners[2]>$corners[4])?$corners[2]:$corners[4]; $top = ($corners[5]>$corners[7])?$corners[7]:$corners[5]; $bottom = ($corners[1]>$corners[3])?$corners[1]:$corners[3]; $width = $right - $left + 4; $height = abs($top - $bottom) + 4; $return = array( 'width' =>$width, 'height' =>$height, 'bottom' =>$bottom, 'right' =>$right, 'top' =>$top, 'left' =>$left ); }else{ $return = false; } return $return; }
Next we will need a functions that will return values in a single form, regardless of the hexadecimal colors of the letters:
function hex2decColor($color){ if(substr_count($color, ',') == 2){ list($red, $green, $blue) = array_map('trim', explode(',', $color)); }else{ $red = hexdec($color[0].$color[1]); $green = hexdec($color[2].$color[3]); $blue = hexdec($color[4].$color[5]); } return array('red'=>$red, 'green'=>$green, 'blue'=>$blue); }
Now we will set the image size to 0 and generate code lenght based on the configured maximum and minimum lenght.
$imgWidth = 0; $imgHeight = 0; $codeLength = rand($minCodeLength, $maxCodeLength);
Next, we will generate $codeLength times a character and it`s properties.
for($c = 1; $c <= $codeLength; $c++){ $char[$c]['char'] = $allowedChars[rand(0, strlen($allowedChars)-1)]; $char[$c]['color'] = hex2decColor($textColor[rand(0, count($textColor)-1 )]); $char[$c]['displacement'] = rand(0, $maxVerticalDisplacement*2) - $maxVerticalDisplacement; $char[$c]['font'] = $fontsFolder.$fontFiles[rand(0, count($fontFiles)-1 )]; $char[$c]['size'] = rand($minFontSize, $maxFontSize); $char[$c]['angle'] = rand(0, $maxRotationLeft + $maxRotationRight) - $maxRotationRight; $char[$c]['space'] = rand($minLetterSpacing, $maxLetterSpacing);
We find out the dimensions of the current character, using one of the functions defined earlier.
$properties = getCharSize($char[$c]['font'], $char[$c]['char'], $char[$c]['size'], $char[$c]['angle']); $width = $properties['width']; $height = $properties['height'];
After we found the width of the character, we add it to the image total width along with the distance to the next character.
$imgWidth += $width; if($c != $codeLength) $imgWidth += $char[$c]['space'];
If the image height is smaller than the current character height, then we set it the correct height.
if( ($height + abs($char[$c]['displacement'])) > $imgHeight ) $imgHeight = $height + abs($char[$c]['displacement']);
We add the current character to the row that forms our code
$_SESSION[$sessionVar] .= $char[$c]['char']; }
Next we add the padding
$imgWidth += $textPadding * 2; $imgHeight += $textPadding * 2 + $maxVerticalDisplacement;
Now, that we set the dimensions, let’s create the image and calculate the background image position. The images can be different textures or landscapes on a higher resolution than our image, so we will need only a portion defined randomly:
$img = imagecreatetruecolor($imgWidth, $imgHeight);
We choose a random image and read the dimensions:
$bg = rand(0, count($backgrounds)-1); list($bgWidth, $bgHeight) = getimagesize($backgroundsFolder.$backgrounds[$bg]);
We set position where the portion of the image begins to be used as background and copy it in our image:
$bgX = rand(0, $bgWidth-$imgWidth); $bgY = rand(0, $bgHeight-$imgHeight); $bgImg = imagecreatefrompng($backgroundsFolder.$backgrounds[$bg]); imagecopy($img, $bgImg, 0, 0, $bgX, $bgY, $imgWidth, $imgHeight); imagedestroy($bgImg);
Next is the code markup inside the image
$cursor = $textPadding;
We set the previously generated color for the current character:
for($c = 1; $c <= $codeLength; $c++){ $color = imagecolorallocate($img, $char[$c]['color']['red'], $char[$c]['color']['green'], $char[$c]['color']['blue']);
We calculate the vertical character, depending on its size and the amount of displacement from the center generated for him:
$properties = getCharSize($char[$c]['font'], $char[$c]['char'], $char[$c]['size'], $char[$c]['angle']); $width = $properties['width']; $height = $properties['height']; $bottom = $properties['bottom']; $y = $char[$c]['displacement'] + $maxVerticalDisplacement + $height - $bottom;
We write the current character and move the cursor to the right:
imagettftext($img, $char[$c]['size'], $char[$c]['angle'], $cursor, $y, $color, $char[$c]['font'], $char[$c]['char']); $cursor += $width + $char[$c]['space']; }
We have left but to apply the Gaussian Blur filter, if the system allows:
if(function_exists('imagefilter')){ imagefilter($img, IMG_FILTER_GAUSSIAN_BLUR); }
At this point, our image is ready and we have to only serve it to a browser, and specify that the image should not be cached by the headers and the format is PNG (can be as good GIF, JPEG or any other format supported by the GD library), then release the resources on the server:
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/png' ); imagepng($img); imagedestroy($img);
Verify! Inside the file that the POST data is sent, we need to open the session using session_start(); and verify that our input data is exactly the same with the saved data. This goes something like this:
if($_SERVER['REQUEST_METHOD'] == 'POST'){ if($_POST['myCaptcha'] == $_SESSION['myCaptcha']){ // The rest of the data is being processed }else{ // Wrong Code! Try Again or Go Away! } }
God, I`m finished
Tips&Triks
To give visitors the opportunity to generate another code without needing to reload the entire page, display the image using the following code:
<img src="show_code.php" alt="myCaptcha" onclick="javascript:this.src += '?';" />
And this is how to create a simple captcha using PHP inside your system.
You may be interested in these also:
4 Comments to “How to make your very own CAPTCHA”
Post comment
Sponsors
Pages
Recent Posts
- 35+ free Icon sets for your next web development project
- Grunge web design tools, brushes and patterns
- Rushhour: WordPress Corporate business blog template
- Autor comment highlight in WordPress 2.8+
- How to create a peel ad in a WordPress blog
- How to make a author box in WordPress
- Best 5 wordpress hosting providers
- A free Photoshop WordPress theme
- 15+ Internet Explorer comics
- How to debug for IE6 with multiple IE instances
- 20+ deviant inspirational design layouts
- How to make your very own CAPTCHA
- 25+ incredible Photoshop makeover videos
- 10 best of the best Joomla themes
- How to set up a hotel reservation form in a WordPress page
Trent says:
You rock! I am gonna try this out. Most *** (greatest) non-abstract tutorial!!
Trent says:
Hi, it’s me again. May I know if there is anyway to set the background image just as it is? Without the portioning.?
Trent says:
May I have my last question please?
-How can I make the letters overlap another one?(decrease text width padding)?
-How do I keep the background image(no random portioning)?
-Refresh button by itself
waiting for your answer~ have been looking for CAPTCHAs this whole week
dan says:
thank you alex for your work, you make a great job, I find more captcha script, but your captcha tutorials is easy to understanding and implement.