View Single Post
Old 12-20-2007, 06:03 PM   #1 (permalink)
CMellor
The Acquainted
Upcoming Programmer 
 
CMellor's Avatar
 
Join Date: Sep 2007
Location: Leeds, UK
Posts: 141
Thanks: 6
CMellor is on a distinguished road
Default [Tutorial] CAPTCHA

If you are un-aware of what CAPTCHA is, please refer to this.

Click for an example!

This is a tutorial on how to make your own CAPTCHA image, and how to use it! Let's begin!

First open up a PHP file, save it to your server and call in captcha.php

We will be using a session variable to store our CAPTCHA code in for later use, so we need to make sure we can use sessions.

PHP Code:
session_start(); 
We're gonna store this code inside a function, though for this particular example, you don't need to, it is optional, but as I say, I will be storing it inside a function.

The function will be called captcha
PHP Code:
function captcha($length 6) { // Start of function 
The $length variable is defaulted to 6, though this can be any number you wish, though I recommend you keep it between 4 and 6.

Tip: if your going to use this with different forms and specify different lengths for each one, then do not specify a length, just keep it as $length

When using the CAPTCHA code, you can specify a length by adding a GET method to your URL to specify how many characters you want your CAPTCHA code to be, but we'll come back to that at the end of this tutorial. We need to check if one is set, otherwise it will be set to it's default number.

PHP Code:
$length = isset($_GET['chars']) ? $_GET['chars'] : 6
Now we need to generate a random string, which will be our random CAPTCHA code. I will do this my getting a complete random number between 0 and 999 and then encrypting it, this will be referred to as the hash.

PHP Code:
$hash md5(rand(0999)); 
Now I know what your thinking, when you encrypt a string, it turns it into a 32 character string, well indeed it does, which is why we trim it down to the length we specified earlier in our$length variable.

PHP Code:
$code substr($hash15$length); 
What this does is takes the random generated hash, starts at the 15th character and trims it down to $length, which in this case, is 6.

Now that we have our random code, we need to store it in a session, which is simple enough.

PHP Code:
$_SESSION["captcha"] = $code
Self explanatory I would think.

Okay! Now onto creating the image. Warning: you must have GD installed on your server.

We need to create the image size, so let's set a width and a height... this can be to any size you wish, but I recommend keeping it at around the size specified in this tutorial, it is a good size.

PHP Code:
$width 200;
$height 50
Now we create our image using the set variables above.

PHP Code:
$image imagecreate($width$height); 
Now just because we can, lets make the image colourful. We'll assign some random RGB (red, green, blue) colours so that on each load, it'll most likely be a different colour. We're not using HEX colours in this, as the function we're using doesn't support it (or at least not that I know of) and to make a colour using RGB, you need to set three numbers between 0 and 255 to get the colour you want. Because we need three numbers, we assign three variables with the same value, because if we set just one variable with the same value, it will always be the same colour.

PHP Code:
$rgb1 rand(0255);
$rgb2 rand(0255);
$rgb3 rand(0255); 
Still with me? Good...

Now we need to colour in our image we made earlier, we do this like so:

PHP Code:
$background imagecolorallocate($image$rgb1$rgb2$rgb3); 
This will make our image a different colour on each reload. Now let's do the same for the text, which is the CAPTCHA code. The only different here is that with the given random number generated, we minus 50 and it gives it more of a transparent look, which trust me, looks good. This is of course optional.

PHP Code:
$text imagecolorallocate($image, ($rgb1 50), ($rgb2 50), ($rgb3 50)); 
Now we have our set variables, we create the final image with our background colour.

PHP Code:
imagefill($image00$background); 
Now we are going to add the random CAPTCHA code to the image. A difference here is the separate characters will be set at an angle, just so that it isn't TOO clear to read, but also not difficult. Also we will use a function that allows you to specify your own font for the image. You'll need to either get a font from your computer, or download one from a website (DAFont.com is a good source for free fonts) and upload it to your server, preferably in the same folder as captcha.php.

To get different angles for the characters, we'll go through a loop and set our $angle variable to be different after each loop (The loop will loop through the amount of times you've specified in the $length variable, in this case, 6.

PHP Code:
for($i 1$i <= $length$i++) {
$counter rand(12);
        
if (
$counter == 1) {
    
$angle rand(045);
}
if (
$counter == 2) {
    
$angle rand(315360);
}
        
imagettftext($imagerand(1420), $angle, ($i 25), 30$text"templates/ChalkboardBold.ttf"substr($code, ($i 1), 1));

What this does, is simply... after a loop has happened, $counter is set to either 1 or 2, if it is 1 then $angle will equal a number between 0 and 45 and if it is 2, it will equal a number between 315 and 360.

Now I'm going to go through the parameters of the imagettftext function.
  • $image is the image you will be using, you specified it earlier
  • This is the size of the font
  • The set angle
  • The X co-ordinates
  • The Y co-ordinates
  • The text colour
  • The path to your font file
  • The text output
Okay so now you should have your image, with a background and font colour, as well as the actual CAPTCHA code on the image as well.

Optional: You could add a border to your image, in my opinion it makes it look better, but as it says, this step is optional. To do this we use a new function called imagerectangle

PHP Code:
imagerectangle($image00$width 1$height 1$text); 
The numbers in this function relate to the upper and lower co-ordinates of X and Y. If you minus 1 from the width and height, it will shrink the image by a pixel and show the rectangle behind it, which gives it the "border" effect.

This step is important, without it you can't view the image, because your working on a PHP file, and the browser will recognise it as a PHP file, and this is an image, so you need to make the browser recognise it as an image, and we do that by using the header function and changing the content type.

PHP Code:
header("Content-Type: image/png"); 
Now the page will act as if it is a PNG file. You could use image/jpg or image/gif if you wish, but for this we're using a PNG.

Now that we have everything done and all put together, we need to output the image using a special function called imagepng, like before, if you decide to use JPG or GIF, change the name of the function to represent your desired extention. (I.E. JPG = imagejpg)

[php]
imagepng($image);
[/php
Now that we have our image done and ready to use, let's free up the resource used and 'destroy' the image (don't worry, it will still show up)

PHP Code:
imagedestroy($image);
// End function 
Something I did after the function was this:

PHP Code:
!isset($_GET['chars']) ? captcha() : captcha($_GET['chars']); 
Basically is chars is not set, it will output the CAPTCHA with the defaulted length, otherwise, it will display it with the number specified by you.

Now save this file, and try it out, open up your browser and point to the file and fingers crossed that it works! Any problems and let us know!

Using the script in your site and verifying it

Ok so you have the script, now you want to use it to prevent attacks on your forms. First get the file with the form you will be using it on. Anywhere in the code, add another input box, this will be used to type in what you see in the CAPTCHA code.

html Code:
<input type="text" name="captcha_confirm" />
Above (or below) that, add your CAPTCHA image to it. As we made the CAPTCHA file into an image, we can use the img tag to display it.

html Code:
<img src="path/to/captcha.php" />
Now you should have your CAPTCHA code displayed, woo!

Verifying

This tutorial assumes that when you submit your form, it uses PHP to process the form to do... whatever it does. Now around the code your using, you need to check if the CAPTCHA matches what was typed in. I will use an example that I did.

PHP Code:
if($_POST['captcha_confirm'] == $_SESSION["captcha"]) {

    
// Update user's e-mail address
    
mysql_query(sprintf("UPDATE members, settings SET
        settings.hide_email = '%d',
        members.email = '%s'
    WHERE members.id AND settings.member_id = '%d'"
,
        (isset(
$_POST['hide_email']) ? 0),
        
$_POST['confirm_email'],
        
$_COOKIE['userID']
    )) or die(
mysql_error());
    
// Above is the code I have... your code will be whatever it was, just wrap the if statement around it
}
else {
    echo 
'Captcha did not match';

Now when you submit your form, and if the CAPTCHA is wrong, you should get an error instead of your code being processed.

So that's all their is to it, I hope this tutorial is helpful to you, if you have any problems, please just ask, we're here to help!

Full code
PHP Code:
<?php
session_start
();
//--------------------
// CAPTCHA Function
//--------------------
function captcha($length 6) {
    
$length = isset($_GET['chars']) ? $_GET['chars'] : 6;
    
    
// Let's generate a totally random string using md5
    
$hash md5(rand(0999)); 
    
// We don't need a 32 character long string so we trim it down to 5 
    
$code substr($hash15$length); 

    
// Set the session to store the security code
    
$_SESSION["captcha"] = $code;

    
// Set the image width and height
    
$width 200;
    
$height 50;

    
// Create the image resource 
    
$image imagecreate($width$height);
    
// Random RGB colours
    
$rgb1 rand(0255);
    
$rgb2 rand(0255);
    
$rgb3 rand(0255);
    
    
$background imagecolorallocate($image$rgb1$rgb2$rgb3);
    
$text imagecolorallocate($image, ($rgb1 50), ($rgb2 50), ($rgb3 50));

    
// Make the background colour
    
imagefill($image00$background); 

    
// Add randomly generated string in the image
    
for($i 1$i <= $length$i++) {
        
$counter rand(12);
        
        if (
$counter == 1) {
            
$angle rand(045);
        }
        if (
$counter == 2) {
            
$angle rand(315360);
        }
        
        
imagettftext($imagerand(1420), $angle, ($i 25), 30$text"templates/ChalkboardBold.ttf"substr($code, ($i 1), 1));
    }

    
// Add a border
    
imagerectangle($image00$width 1$height 1$text); 
 
    
// Tell the browser what kind of file is come in 
    
header("Content-Type: image/png"); 

    
// Output the newly created image in jpeg format 
    
imagepng($image);
   
    
// Free up resources
    
imagedestroy($image); 
}

!isset(
$_GET['chars']) ? captcha() : captcha($_GET['chars']);
?>
__________________
Not quite a n00b...
CMellor is offline  
Reply With Quote
The Following 6 Users Say Thank You to CMellor For This Useful Post:
Andrew (12-20-2007), Gurnk (12-21-2007), Rendair (12-20-2007), sketchMedia (12-21-2007), Village Idiot (12-21-2007), Wildhoney (12-20-2007)