jump to navigation

Image Auth – CAPTCHA component March 16, 2006

Posted by rossoft in CakePHP.
trackback

A human verification system through a text image

1. Include the component.
var  $components =array (‘xxx’,’yy’,’imageAuth’);

2. In the login action:
$this->imageAuth->generate();

3.
Create a new action for showing the image: /login/image_auth
function image_auth()
{
    $this->imageAuth->show();
}

4.
In the login form:
<img src=”<?=$html->url(’/login/image_auth’)?>” />

5. Put this in vendors/image_auth/

6. In your post-action:

if (! $this->imageAuth->check( $this->params[‘data’][‘text’] ))
{
    echo ‘Wrong text entered’;
}

7. Put this code in controllers/components/image_auth.php
<?php
/*
 * Image Auth component.
 * Real human verification system for forms
 *
 * @author      RosSoft
 * @version     0.1
 * @license        MIT
 *
 * @link http://phpbuilder.com/columns/patterson20060301.php3
 */
class ImageAuthComponent extends Object
{
    var $components = array(‘session’);
    var $controller;
   
    /** Font file */
    var $font=’ProggyCleanSZBP’;
   
    /** some background colors */
    var $bg_colors = array(
                                    ‘176.196.222’, // Blue
                                    ‘204.153.204’, // Purple
                                    ‘204.204.204’, // Gray
                                    ‘227.81.82’,     // Red
                                    ‘150.200.162’  // Green
                                    );
                                   
    /** Some font colors */
    var $font_colors = array(
                                    ‘0.0.139’, // Blue
                                    ‘104.34.139’, // Purple
                                    ‘79.79.79’, // Gray
                                    ‘128.0.0’, // Red
                                    ‘59.94.15’     // Green
                                    );
    /** Image width */                                
    var    $img_width = 170;
   
    /** Image height */
    var $img_height = 75;
   
    /** Font size */
    var $fnt_size = 24;
   
    /** Letter spacing */
    var $let_space = 10;

    /** Length of random string */       
    var $str_length = 6;
                                                           

    function startup(&$controller)
    {
        $this->controller=$controller;       
    }
   
    /**
     * Generates a new random string and stores on session
     * @param boolean $regenerate. If false and already exists a random string then it’s reused
     */   
    function generate($regenerate=true)
    {
        if (! $regenerate)
        {
            $regenerate= ! $this->session->check(‘image_auth_string’);
        }   
        if ($regenerate)
        {
            $rnd_str = $this->_gen_random_string($this->str_length);   
            $this->session->write(‘image_auth_string’,$rnd_str);       
        }
                   
    }
   
    /**
     * Outputs the random string as an image.
     * The string is readed from the session
     */
    function show()
    {
        $this->generate(false); //Generates a new string if there isn’t a generated one
        $rnd_str=$this->session->read(‘image_auth_string’);
       
        // Set GD font path
        putenv(‘GDFONTPATH=’.realpath(VENDORS . ‘image_auth’));
        /**
         * Image functions
         */
        // Create the image
        $img = imagecreate($this->img_width, $this->img_height) or die(‘Can not initialize GD Image Library’);

        // Define Background & Text colors
        list($br, $bg, $bb) = explode(‘.’, $this->bg_colors[rand(0, count($this->bg_colors)-1)]);
        list($tr, $tg, $tb) = explode(‘.’, $this->font_colors[rand(0, count($this->font_colors)-1)]);
        $bg_color = imagecolorallocate($img, $br, $bg, $bb);
        $txt_color = imagecolorallocate($img, $tr, $tg, $tb);
        $line_clr = imagecolorallocate($img, 0, 0, 0);
        // Create box around image
        imageline($img, 0, 0, $this->img_width, 0, $line_clr); // Top left to top right
        imageline($img, 0, 0, 0, $this->img_height, $line_clr); // Top left to bottom left
        imageline($img, 0, $this->img_height-1, $this->img_width, $this->img_height -1, $line_clr); // Bottom Left to Bottom right
        imageline($img, $this->img_width-1, 0, $this->img_width-1, $this->img_height, $line_clr); // Top right to bottom Right

        //     Write string into image
        for($i=0; $i
        {
            imagettftext($img, (rand() % $this->fnt_size / 1.5) + $this->fnt_size, rand(-30, 30), (($i*$this->fnt_size)+$this->let_space), rand($this->fnt_size+5, ($this->img_height – $this->fnt_size-5)), $txt_color, $this->font, $rnd_str{$i});
        }
        imagefilter($img,IMG_FILTER_GAUSSIAN_BLUR,200);
           header(“Pragma: public”);
           header(“Expires: 0”);
           header(“Cache-Control: no-store, no-cache”);
           header(“Cache-Control: must-revalidate, post-check=0, pre-check=0”);
           header(“Cache-Control: public”);
        if (function_exists(‘imagepng’))
        {
            header(“Content-type: image/png”);
            imagepng($img);
        }
        else
        {
            header(“Content-type: image/jpeg”);
            imagejpeg($img);
        }
        $this->controller->autoRender=false;
    }
   
    /**
     * Checks the string passed against session for a valid auth
     * @param string $string String to be checked
     * @return boolean. True if valid  
     */   
    function check($string)
    {
        return ($string === $this->session->read(‘image_auth_string’));
    }

   
    /**
     * Random string generation function
     */
    function _gen_random_string($length=5, $str=”)
    {
        for($i=1; $i<=$length; $i++)
        {
            $ord = rand(48, 90);

            if( ( ($ord>=48) && ($ord<=57) ) || ( ($ord>=65) && ($ord<=90) ) )
            {
                $str .= chr($ord);
            }
            else
            {
                $str .= $this->_gen_random_string(1);
            }
        }
        return $str;
    }   
}

Advertisements

Comments»

1. Gustavo Carreno - March 17, 2006

You have a typo:
if (function_exists(’imagegng’))
Should be:
if (function_exists(’imagepng’))

Beside that, it’s quite an awsome feature !!
Thanks !!

2. rossoft - March 17, 2006

thanks, i’ve corrected the code

3. Felix Geisendörfer - March 20, 2006

Hi RosSoft,

while I appreciate your work on this I think it shouldn’t be used. The reason is that captchas are more effective with blocking blind people then they are for bots.

Bots (can) use two technics for spaming a captcha protected site:
– They can use some graphic recognition to read it -> check out http://sam.zoy.org/pwntcha/ if you don’t believe it.
– They present one of your captcha’s to a human user on some fake website (most likely xxx) and will use humans to easily solve tons of captchas

So what else should be used? While there is no ultimate weapon against spam bots the following techniques are fairly good:
– Create some input fields that should stay empty and hide them with css -> only bot’s will fill them out automatically. (Name them ’email’ to make them appear extra juicy to the bot.
– Use unique form id’s for every request. Most most bots won’t reload your page for every attack and will cache your form fields the first time
– Use simple filters to block post’s containing links and the word viagra … ; )

cheers, Felix Geisendörfer, aka the_undefined

4. Olegs - March 25, 2006

Near
// Write string into image

Should be

for($i=0; $i

5. Olegs - March 25, 2006

Near
// Write string into image
Should be
for($i=0; $i<strlen($rnd_str); $i++)

Also
imagefilter($img,IMG_FILTER_GAUSSIAN_BLUR,200);

Is available for PHP 5 only

Thanks for the good component.

6. rossoft - March 25, 2006

thanks, after editing some mistakes anothers appear… the tags are deleted.

imagefilter is optional, isn’t necessary

7. Kacperix - August 21, 2006

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/lovers/ftp/app/controllers/components/image_auth.php on line 107

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 110

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 111

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 112

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 113

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 114

Warning: Cannot modify header information – headers already sent by (output started at /home/lovers/ftp/app/controllers/components/image_auth.php:107) in /home/lovers/ftp/app/controllers/components/image_auth.php on line 117
�PNG 

8. Kacperix - August 21, 2006

Ohhh…this up is my problem…and I don’t know what I must do that this will working.

9. rossoft - August 23, 2006

You need a true type font. put a some ttf font in vendors/image_auth/ , then modify the variable var $font to match the font name

10. Gleny - December 11, 2006

I follow the instructions but I have a problem, I don’t get the image 😦

11. zef - February 2, 2007

oh wow, thanks for the code! 🙂

12. lukemack - February 6, 2007

can you confirm that:

– the component should be included in the controller?
– this will work under php4?
– should the URL http://path to login controller/image_auth/ produce the image?

i can’t get this to work. i want it to appear in /users/register and have added url(‘/users/register/image_auth’)?>” /> to the register view. I have the TTF in /vendors/image_auth/.

I have added the imaget_auth function to the users controller and my register function looks like this:

function register()
{
$this->imageAuth->generate();
$this->set(‘username_error’, ‘Username must be between 6 and 40 characters.’);
if (!empty($this->data))
{
if ($this->User->validates($this->data))
{
if (! $this->imageAuth->check( $this->params[‘data’][‘text’] ))
{
echo ‘Wrong text entered’;
}
if ($this->User->findByUsername($this->data[‘User’][‘username’]))
{
$this->User->invalidate(‘username’);
$this->set(‘username_error’, ‘User already exists.’);
} else {
$this->data[‘User’][‘password’] = md5($this->data[‘User’][‘password’]);
$this->User->save($this->data);
$this->Session->write(‘user’, $this->data[‘User’][‘username’]);
$this->redirect(‘/users/index’);
}
} else {
$this->validateErrors($this->User);
}
}
}

13. Ian - March 4, 2007

I also can’t get this to work. Although it does work if I alter it a bit and have it create an image on the filesystem:

imagejpeg($img, WWW_ROOT . ‘img/tmp/test.gif’);

then you just need to make sure that there is a tmp directory under the img dir in your webroot, and make sure that your webserver account has write permissions in that dir. Although it would be best if I could get it working as above, and have the image just streamed to the browser instead of having it stored on the filesystem and then pointing my views to it. Anyone get it working as above? It just gives me a blank image…

I also had the issue of the “Could not find/open font ” stated in a comment here. The problem was that this script by default looks into the cake vendor directory, and not the vendor directory in your apps dir (which is where I placed the TTF file). A simple change got that working for me also:

putenv(‘GDFONTPATH=’ . realpath(APP . ‘vendors/image_auth’));

that way the GDFONTPATH points to my vendors directory in my app dir.

14. jenson - June 21, 2007

i got this error what can i do.
The image “http://localhost/cake_php/tests/image_auth” cannot be displayed, because it contains errors.Please give me the solution.

15. Shaun - July 22, 2007

To Jenson:

Make sure that you have your DEBUG definition set to 0 in config/core.php . Also, make sure the font file you have is OK. If you have DEBUG set to 1 and need to see what’s going on, make some other action in your controller that spits out an HTML link to image_auth.

16. Darren - January 22, 2008

Hey dude your code is messed up! Post it better!

17. Jermy - March 26, 2008

iam not getting the solution to this message

Warning: imagettftext()

kindly help

18. PFWD - April 18, 2008

Good Work. But i think you should use a code highlighter to stop those smilies showing.

19. kristofer - June 25, 2008

the link to the image isn’t working anymore.. 😦

20. vcxvxc - October 21, 2008

dfdsfdsf

21. nyeks - February 4, 2009

nyeksadasdsa

22. rahmani - February 9, 2009

in the name of allah

output:

in the name of allah
Warning: Cannot modify header information – headers already sent by (output started at /var/www/html/graphic.php:2) in /var/www/html/graphic.php on line 3
�PNG  ��� IHDR������������UZ���PLTE����x�W���IDATH�������à�S��U�����<�MV%����IEND�B`�

23. rahmani - February 9, 2009

program code

in the name of allah

output

n the name of allah
Warning: Cannot modify header information – headers already sent by (output started at /var/www/html/graphic.php:2) in /var/www/html/graphic.php on line 3

24. Использование reCaptcha в CakePHP | Meelky Blog - February 28, 2009

[…] как предыдущая. Этот компонент я нашёл в блоге Rossoft где вы наверняка сможете найти для себя много […]

25. Pradnya - March 26, 2009

hey Janson have you got the solution to your problem..i am also getting the same error??
“The image http://localhost/tests/users/image_auth cannot be displayed because it contains errors”
Please help!!

26. RaiulBaztepo - March 29, 2009

Hello!
Very Interesting post! Thank you for such interesting resource!
PS: Sorry for my bad english, I’v just started to learn this language 😉
See you!
Your, Raiul Baztepo

27. moi - May 18, 2009

?

28. jafar - January 13, 2012

even i cant see what the iamge in your captch example

29. Krystyna - May 11, 2013

Good way of explaining, and nice piece of writing to get data regarding
my presentation subject, which i am going to present in university.

30. Johng744 - September 16, 2014

I do trust all of the ideas you’ve presented in your post. They’re very convincing and can certainly work. Nonetheless, the posts are very short for beginners. May just you please lengthen them a bit from next time? Thanks for the post. fdccfebgebgc


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: