Results 1 to 10 of 10

Thread: Creating Image validation for Forms

  1. #1
    Join Date
    Jan 2007
    Posts
    629
    Thanks
    10
    Thanked 28 Times in 28 Posts

    Default Creating Image validation for Forms

    Create image validation

    In this tutorial:
    • Create your own (simple) version of CAPTCHA
    • Learn about PHP image functions


    What you need:
    • A basic knowledge of PHP
    • A PHP Enabled server
    • 30 minutes


    What is image validation?

    You've most likely seen by those annoying forms with CAPTCHA-- "Please type the characters in the image" they say. The concept behind them is simple: computers cannot read like humans can, so by forcing a user to read something and copy it, it should prevent computers from posting information to a server. While some of them are extremely hard to read, they generally work well for weeding out the pesky web bots. Actually, they also effectively block form submissions that are not coming from your website. No, they aren't perfect, but they generally work well.

    So, what are we waiting for? Lets make a simple one using PHP to help protect our forms.

    Our string

    First, we need to generate the characters to place in our image. Take a look at this:
    PHP Code:
    <?php
        SESSION_START
    ();
        
    $_SESSION['captcha'] = '';
        
    $captcha_chars = array('2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','M','N','P','Q','R','S','Y','U','V','W','X','Y','Z');
        for(
    $i 0$i 5$i++){
             
    $rand_char rand(0, (count($captcha_chars) -1));
            
    $_SESSION['captcha'] .= $captcha_chars[$rand_char];
        }
    ?>
    (Notice that similar characters like 0 and O, and I and 1 have been removed from the array so the user does not get confused.)

    That block of code should be self explanatory, but just in case, I'll briefly explain. We are starting a session to store the string in so that our image and the form validation process can have access to the string. Then, we generate five random characters via the rand() function.

    With that out of the way, we are going to need to use PHP's relatively decent image functions.

    The image

    Let's create an image. To do this, we start by calling the function createimage().
    PHP Code:
    $im imagecreate(20060); 
    Here we have declared our image to be 200px in width, and 60px in height.

    Lets create some colors for our image:
    PHP Code:
    $bg_color imagecolorallocate($im012287); //This is the bg color
    $font_color imagecolorallocate($im000); 
    Okay, lets stop and see what we've done so far. By adding three more lines of code to the end, we can see our image:
    PHP Code:
    <?php
        SESSION_START
    ();
        
    $_SESSION['captcha'] = '';
        
    $captcha_chars = array('2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','M','N','P','Q','R','S','Y','U','V','W','X','Y','Z');
        for(
    $i 0$i 5$i++){
             
    $rand_char rand(0, (count($captcha_chars) -1));
            
    $_SESSION['captcha'] .= $captcha_chars[$rand_char];
        }

        
    $im imagecreate(20060);

        
    $bg_color imagecolorallocate($im012287);
        
    $font_color imagecolorallocate($im000);

        
    header("Content-type: image/png"); // We are telling the browser that there is an image coming
        
    imagepng($im); // Now we are outputting the image
        
    imagedestroy($im); // Now we are deleting the image resource
    ?>
    Wasn't that fun? Hopefully the code is working and you see a small image. If not, now is the time to rewind the tape and correct your mistakes so far.

    Drum roll please. We are about to add the text! First, we need to change the string into an array of single characters. I prefer preg_split(), but you can use whatever you like:
    PHP Code:
    $characters preg_split("//"$_SESSION['captcha'], -1PREG_SPLIT_NO_EMPTY); 
    (Notice the PREG_SPLIT_NO_EMPTY flag on the end-- we don't want any blank characters).

    And here is where it gets tricky. Find the Arial font and place it in the folder with the script, because we need it for inserting the text. Once you've done that, your ready for this:
    PHP Code:
        $x 5// Start the characters 5px from left
        
    foreach($characters as $char){
            
    $y rand(25,45); // Y cord or char
            
    $size rand(16,28); // Font size for char
            
    $rotation rand(-17,17); // Rotation of char
            // INSERT CHAR HERE IN A MINUTE
            
    $x += 38// X cord of char
        

    So far all this does is set of some random params for the character to be inserted. To insert the text, we use a somewhat confusing function called imagettftext(). Here is how we will use it:
    Code:
    imagettftext($im, $size, $rotation, $x, $y, $font_color, './arial.ttf', $char);
    The big finish

    Thus, our finished code is something like this:
    PHP Code:
    <?php
        SESSION_START
    ();
        
    $_SESSION['captcha'] = '';
        
    $captcha_chars = array('2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','M','N','P','Q','R','S','Y','U','V','W','X','Y','Z');
        for(
    $i 0$i 5$i++){
             
    $rand_char rand(0, (count($captcha_chars) -1));
            
    $_SESSION['captcha'] .= $captcha_chars[$rand_char];
        }

        
    $im imagecreate(20060);

        
    $bg_color imagecolorallocate($im012287);
        
    $font_color imagecolorallocate($im000);


        
    $characters preg_split("//"$_SESSION['captcha'], -1PREG_SPLIT_NO_EMPTY);
        
        
    $x 5;
        foreach(
    $characters as $char){
            
    $y rand(25,45);
            
    $size rand(16,28);
            
    $rotation rand(-17,17);
            
    imagettftext($im$size$rotation$x$y$font_color'./arial.ttf'$char);
            
    $x += 38;
        }

        
    header("Content-type: image/png");
        
    imagepng($im);
        
    imagedestroy($im);

    ?>
    If you want to get fancy, you can add random lines or a background image, but that's beyond this tutorial.

    To insert the image into your form, place this next to the text input in which you wish the have the user type the captcha string:
    Code:
    <img src="./path_to_script/script_name.php" />
    To check against the users input, do something like this in the form process:
    Code:
    if($_POST['captcha'] != $_SESSION['captcha']){die('Incorrect captcha entry');}
    Thanks for reading this, and I hope you learned something.

    EDIT:
    ----------------------
    djr33 was kind enough to put a modified version of the script online. The online version features some distortion.
    http://ci-pro.com/misc/jascaptcha -- View retult
    http://ci-pro.com/misc/jascaptcha/code.txt -- View code
    Last edited by Jas; 07-06-2008 at 12:37 AM.
    --Jas
    function GreatMinds(){ return "Think Like Jas"; }
    I'm gone for a while, but in the meantime: Try using my FTP script | Fight Bot Form Submissions

  2. #2
    Join Date
    Jan 2008
    Posts
    4,167
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    Another way would be to add a hidden field like this:
    HTML Code:
    <input type="hidden" name="comfirm_email">
    And since it's hidden, humans wont see it, but bots will fill it out.
    I made my own little "big finish":
    PHP Code:
    <?php
        SESSION_START
    ();
        
    $_SESSION['captcha'] = '';
        
    $captcha_chars = array('2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','M','N','P','Q','R','S','Y','U','V','W','X','Y','Z');
        for(
    $i 0$i 5$i++){
             
    $rand_char rand(0, (count($captcha_chars) -1));
            
    $_SESSION['captcha'] .= $captcha_chars[$rand_char];
        }
        
    header("Content-type: image/png");
        
    $im imagecreate(20060);

        
    $bg_color imagecolorallocate($im012287);

        
    $characters preg_split("//"$_SESSION['captcha'], -1PREG_SPLIT_NO_EMPTY);
        
        
    $x 5;
        foreach(
    $characters as $char){
            
    $y rand(25,45);
            
    $size rand(16,28);
            
    $rotation rand(-17,17);
            
    imagettftext($im$size$rotation$x$yimagecolorallocate($imrand(0,20), rand(0,210), rand(0,20)), 'phpower/fonts/arial.ttf'$char);
            
    imageline($im$size*rand(0,5), $rotation-rand(0,5), $x+rand(0,3), $y-rand(0,3), imagecolorallocate($imrand(0,122), rand(0,122), rand(0,122)));
            
    $points = array(rand(0,200), rand(0,200), rand(0,200),rand(0,200), rand(0,200), rand(0,200), rand(0,200), rand(0,200), rand(0,200), rand(0,200));
            
    $vertices count($points) / 2;
            
    imagepolygon($im$points$verticesimagecolorallocate($imrand(0,255), rand(0,255), rand(0,255)));

            
    $x += 38;
        }

        
    imagepng($im);
        
    imagedestroy($im);

    ?>
    Last edited by Nile; 07-04-2008 at 04:57 PM.
    Jeremy | jfein.net

  3. #3
    Join Date
    Jan 2007
    Posts
    629
    Thanks
    10
    Thanked 28 Times in 28 Posts

    Default

    Interesting thought, Nile. Do bots fill out hidden feilds, or would you need to do something more like:

    Code:
    <input type="text" name="comfirm_email" style="display:none;">
    ?
    --Jas
    function GreatMinds(){ return "Think Like Jas"; }
    I'm gone for a while, but in the meantime: Try using my FTP script | Fight Bot Form Submissions

  4. #4
    Join Date
    Jan 2008
    Posts
    4,167
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    I think either would work. Editted my above post for my own "big finish".
    Jeremy | jfein.net

  5. #5
    Join Date
    Jan 2007
    Posts
    629
    Thanks
    10
    Thanked 28 Times in 28 Posts

    Default

    Glad my code inspired you I wasn't going to go that far in the tutorial, but what the heck. Two things, though: 1) most of the lines and polygons should probably be inserted before the characters, otherwise it will cover the characters which might make them really hard to read. 2) You might want to make your code more readable for those just starting with image functions. (i.e. generate the numbers outside of the functions, add comments, etc.).

    That is a great contribution to the tutorial.
    --Jas
    function GreatMinds(){ return "Think Like Jas"; }
    I'm gone for a while, but in the meantime: Try using my FTP script | Fight Bot Form Submissions

  6. #6
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,162
    Thanks
    263
    Thanked 690 Times in 678 Posts

    Default

    Bots aren't intelligent enough to go looking for a page and try to break the encryption. That's not the strategy.
    A bot is likely custom designed for a page.

    So if it can be programmed to ignore your "trick" then that's not very useful. Sure, it's a bit better than the standard spam, but that can be accomplished with minimal effort, like "check this box to show you're not a bot!".

    Do you have a demo page up for the captcha?

    I wrote a couple distortion filters for captchas to improve them on my forum, at one point. I could add those here, if it needs it.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  7. #7
    Join Date
    Jan 2007
    Posts
    629
    Thanks
    10
    Thanked 28 Times in 28 Posts

    Default

    No demo page, sorry. I don't have any web space as of yet to do things like that. If someone would like to volunteer to post the code on their site, I would very much appreciate it. Just let me know via a post or PM so I can link to it in the original post.

    As far as the distortion filters go, my intention was to keep the tutorial as simple as possible to give people an idea of how programs like CAPTCHA work (kind of a point in the right direction, if you will). If you think it's simple enough for this tutorial, please feel free to post that information. I would like to see the code myself . (Right now all the code does is create random characters that are random sizes and position them randomly. All the characters are clearly visible, though.)
    --Jas
    function GreatMinds(){ return "Think Like Jas"; }
    I'm gone for a while, but in the meantime: Try using my FTP script | Fight Bot Form Submissions

  8. #8
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,162
    Thanks
    263
    Thanked 690 Times in 678 Posts

    Default

    Ok, here's a demo, including the distortion.

    http://ci-pro.com/misc/jascaptcha
    http://ci-pro.com/misc/jascaptcha/code.txt

    The values are all adjustable. I'll try to write up a bit on that later.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  9. #9
    Join Date
    Jan 2007
    Posts
    629
    Thanks
    10
    Thanked 28 Times in 28 Posts

    Default

    Thanks, Daniel, but there is a serious problem with the script. Since you are generating both the bg and the fg randomly, sometimes the colors are similar and you can't see the text. When I viewed it, 2 out of ten could not be seen clearly enough to make out.

    I don't have time now, but I can try to write something up to fix that later, if you like. I am thinking that you just need to generate three random numbers (r, g, b) for the bg color, and create an algorythm to invert the color the color for the text.
    --Jas
    function GreatMinds(){ return "Think Like Jas"; }
    I'm gone for a while, but in the meantime: Try using my FTP script | Fight Bot Form Submissions

  10. #10
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,162
    Thanks
    263
    Thanked 690 Times in 678 Posts

    Default

    The inverted color is already used for the random lines.

    I'm aware of the problem, too, but I didn't have time to think about it too much. Basically, you can loop through random colors to be sure the contrast is high enough. That's possible.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •