How to create captcha in PHP using GD library

How to create captcha in PHP using GD library

12 125

How to create captcha in PHP using GD library

Today I will tell you about very important thing – captcha protection. Usually this is very important to prevent automated sign-ups in your registration forms, comment spam in blogs and guestbooks, or another brute force attacks. I will give sample how to draw protection image using our hands.

Here are samples and downloadable package:

Live Demo
download in package

Ok, download the example files and lets start coding !


Step 1. HTML

As usual, we start with the HTML.

This is our main page code.

index.html

<script src="js/jquery.min.js"></script>
<script src="js/md5.js"></script>

<script src="js/main.js"></script>
<link rel="stylesheet" href="templates/css/main.css" type="text/css" />

<div class="captcha_example">
    <h3><a href="#">Captcha generation using GD, using MD5 to encrypt security text</a></h3>
    <div>
        <div style="margin-bottom:10px;">
            <h4>Security image:</h4>

            <img src="captcha.php" class="form_captcha" />
            <div class="lines">Verification (Type what you see):</div>
            <input type="text" name="captcha" value="" class="captcha" />
            <button onclick="checkCaptcha()">Check it</button>
        </div>
        <p>
            Current sample draw security image using GD library, each time when page loads it show different symbol-digit combinations. This combination processing through MD5 encription and storing in cookies. So you will able to check cookies after (where it necessary). In my sample I checking it using javascript. Try it!
        </p>
    </div>
</div>

To display captcha (security image) we will just draw image with php-source: captcha.php. It will generate image for us. Generated text will processed via MD5 and stored in cookies to following recognition and checking.

Step 2. CSS

Here are used CSS styles.

templates/css/main.css

body{background:#eee;font-family:Verdana, Helvetica, Arial, sans-serif;margin:0;padding:0}
.captcha_example{background:#FFF;width:865px;font-size:80%;border:1px #000 solid;margin:0.5em 10% 0.5em;padding:1em 2em 2em;-moz-border-radius: 3px;-webkit-border-radius: 3px}
.lines{margin:10px 0}

Step 3. JS

Here are necessary JS files to our project.

js/main.js

function getCookie(c_name) {
    if (document.cookie.length>0) {
        c_start=document.cookie.indexOf(c_name + "=");
        if (c_start!=-1) {
            c_start=c_start + c_name.length+1;
            c_end=document.cookie.indexOf(";",c_start);
            if (c_end==-1) c_end=document.cookie.length;
            return unescape(document.cookie.substring(c_start,c_end));
        }
    }
    return "";
}

function checkCaptcha() {
    // check captcha
    var sInsCaptcha = calcMD5($('.captcha').val());
    var sCookieCaptcha = getCookie('strSec');

    if (sInsCaptcha == sCookieCaptcha) {
        alert('Wow, great, you enter correct captcha');
    } else {
        alert('Sorry, but wrong');
    }
}

We will using getCookie function to get cookies information, and checkCaptcha to validate captcha.

js/jquery.min.js and js/md5.js

This is common files – jQuery library with addon for working with MD5. No need to give full code of that file here. It always available as a download package

Step 4. PHP

Ok, here are all used PHP file:

index.php

<?php

ob_start();
$chars = array("a","A","b","B","c","C","d","D","e","E","f","F","g","G","h","H","i","I","j","J",
               "k","K","L","m","M","n","N","o","p","P","q","Q","r","R","s","S","t","T",
               "u","U","v","V","w","W","x","X","y","Y","z","Z","2","3","4","5","6","7","8","9");

$textstr = '';
for ($i = 0, $length = 5; $i < $length; $i++)
   $textstr .= $chars[rand(0, count($chars) - 1)];

$hashtext = md5($textstr);
setcookie('strSec', $hashtext, 0, '/');
if (produceCaptchaImage($textstr) != IMAGE_ERROR_SUCCESS) {
    // output header
    header( "Content-Type: image/gif" );

    header("Expires: Mon, 21 Jul 2010 05:00:00 GMT");
    header("Last-Modified: " . gmdate("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" );

    // output error image
    @readfile('captcha/captcha_error.gif');
}
ob_end_flush();


function produceCaptchaImage($text) {
    // constant values
    $backgroundSizeX = 2000;
    $backgroundSizeY = 350;
    $sizeX = 200;
    $sizeY = 50;
    $fontFile = "captcha/verdana.ttf";
    $textLength = strlen($text);

    // generate random security values
    $backgroundOffsetX = rand(0, $backgroundSizeX - $sizeX - 1);
    $backgroundOffsetY = rand(0, $backgroundSizeY - $sizeY - 1);
    $angle = rand(-5, 5);
    $fontColorR = rand(0, 127);
    $fontColorG = rand(0, 127);
    $fontColorB = rand(0, 127);

    $fontSize = rand(14, 24);
    $textX = rand(0, (int)($sizeX - 0.9 * $textLength * $fontSize)); // these coefficients are empiric
    $textY = rand((int)(1.25 * $fontSize), (int)($sizeY - 0.2 * $fontSize)); // don't try to learn how they were taken out

    $gdInfoArray = gd_info();
    if (! $gdInfoArray['PNG Support'])
        return IMAGE_ERROR_GD_TYPE_NOT_SUPPORTED;

    // create image with background
    $src_im = imagecreatefrompng( "captcha/background.png");
    if (function_exists('imagecreatetruecolor')) {
        // this is more qualitative function, but it doesn't exist in old GD
        $dst_im = imagecreatetruecolor($sizeX, $sizeY);
        $resizeResult = imagecopyresampled($dst_im, $src_im, 0, 0, $backgroundOffsetX, $backgroundOffsetY, $sizeX, $sizeY, $sizeX, $sizeY);
    } else {
        // this is for old GD versions
        $dst_im = imagecreate( $sizeX, $sizeY );
        $resizeResult = imagecopyresized($dst_im, $src_im, 0, 0, $backgroundOffsetX, $backgroundOffsetY, $sizeX, $sizeY, $sizeX, $sizeY);
    }

    if (! $resizeResult)
        return IMAGE_ERROR_GD_RESIZE_ERROR;

    // write text on image
    if (! function_exists('imagettftext'))
        return IMAGE_ERROR_GD_TTF_NOT_SUPPORTED;
    $color = imagecolorallocate($dst_im, $fontColorR, $fontColorG, $fontColorB);
    imagettftext($dst_im, $fontSize, -$angle, $textX, $textY, $color, $fontFile, $text);

    // output header
    header("Content-Type: image/png");

    // output image
    imagepng($dst_im);

    // free memory
    imagedestroy($src_im);
    imagedestroy($dst_im);

    return IMAGE_ERROR_SUCCESS;
}

?>

Here are several comments by code:

In start we will define array of used characters – $chars. After, we will compose string (5 letters) with random characters. After, will MD5 this result string and save it into cookies. We will use this to more security. So any bot or special script will unable to find this key even after detail investigation of result page.

produceCaptchaImage is main function which will draw our captcha. It take just 1 param – text which we going to draw. We will using GD library to draw. We will randomly choose position to text in captcha, angle (+- 5 degrees), font color. After will get our background image which will mage reading of our code more difficult, and, will draw result text on this image.


Live Demo
download in package

Conclusion

Today I told you how to create our own captcha – security image. I sure that you will use it in your projects. Quite any serious project using it to protect spamming. Good luck!

SIMILAR ARTICLES


12 COMMENTS

    • Yes, I know, firebug give us big possibilities. But I gave main conception. You can just submit some form with captcha, and check this validation directly at server using PHP. All possible ;-)

  1. Just saying thanks will not just be sufficient, for the tremendous lucidity in your posts. I will right away grab your feed to stay abreast of any updates. Many posts are very dry and hard to read, but yours has been very well written and informational!

  2. Bookmarked good sir! Also, love the code snippets. Is it a plugin that lets you do that? I’ve seen it around.

    • 2 Raju Khatak
      Check our JS file, where I alerting about success, in this place you can allow to submit your form !

  3. I am creating a test form first before putting it on my site. So far everything works OK but I wish the user to be redirected when clicking OK in the ‘yes’ alert. I have put a location in the javascript but it just goes back to the a refreshed form and not to the required location. Below is the relevant section of main.js, what am I doing wrong?
    ——————

    function checkCaptcha() {
    // check captcha
    var sInsCaptcha = calcMD5($(‘.captcha’).val());
    var sCookieCaptcha = getCookie(‘strSec’);

    if (sInsCaptcha == sCookieCaptcha) {
    window.alert(‘Click OK to submit’)
    window.location.href = ‘custom_website_url’;
    } else {
    alert(‘Sorry, but wrong’);
    }
    }

    • Hello Andrew,
      Your changes are correct, I’ve just tested it and it relocates to another url once you enter a correct captcha

  4. Excellent work, thank you! I just replaced my sometimes-working CAPTCHA code with your produceCaptchaImage() routine and all was ready and working. :-) (with server side check, of course, but I had that part already, just had troubles with image creating). Thanks!

    Hm, by the way, some of those error constants were undefined for me, but I simply changed it to return true/false.

Leave a Reply