Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "captcha"

Simple CAPTCHA

Hi!

This code is about a very simple CAPTCHA validation. I am pretty sure that you all know what CAPTCHA is, so I won't explain it. This CAPTCHA is based on the color-blindness test that operates with various colored balls.

The class:

class Captcha
{
    protected $value;
    protected $image_name;
 
    public function __construct( $image_name )
    {
        $this->image_name = $image_name;
    }
 
    public static function createNumber( $length = 4 )
    {
        $num = "";
        for ( $i = 0; $i < $length; $i++ )
        {
            $r = mt_rand( 0, 9 );
            $num = $num.$r;
        }
        return $num;
    }
 
    public static function createString( $length = 4 )
    {
        $val = "";
        $values = "abcdefghijklmnopqrstuvwyz";
        for ( $i = 0; $i < $length; $i++ )
        {
            $r = mt_rand( 0, 24 );
            $val = $val.$values[$r];
        }
        return $val;        
    }
 
    public function setValue( $value )
    {
        $this->value = $value;
    }
 
    public function getValue( )
    {
        return $this->value;
    }
 
    public function showImage( $channel = null )
    {
        $im = imageCreate( 160, 60 );
        $white = imagecolorallocate( $im, 255, 255, 255 );
        $black = imagecolorallocate( $im, 0, 0, 0 );
 
        $intensity = rand ( 200, 230 );
 
        if ( !$channel )
        {
            $channel = rand ( 1, 3 );
        }
        $ratio = rand ( 80, 100 );
 
        switch ( $channel )
        {
                case 1:
                        $colorBgR = $intensity * $ratio / 100;
                        $colorBgG = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgB = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ( $i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $new, $intensity-$new, 0 );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*7, 100 + ( $i+1)*7 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $intensity-$new, $new, 0 );
                        }
                break;
 
                case 2:
                        $colorBgG = $intensity * $ratio / 100;
                        $colorBgB = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgR = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ($i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, 0, $new, $intensity-$new );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*7, 100 + ( $i+1)*7 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, 0 , $intensity-$new, $new );
                        }
 
                case 3:
                        $colorBgB = $intensity * $ratio / 100;
                        $colorBgR = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgG = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ( $i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $intensity-$new, 0, $new );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                            // to make it harder do symmetric range ^^ 
                                $shift = rand( 100 , 100 + ( $i+1)*20 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $new , 0, $intensity-$new );
                        }
                break;
        }
 
 
 
 
        $bgColor = imagecolorallocate( $im, $colorBgR, $colorBgG, $colorBgB );
 
 
        for ( $i = 0; $i < strlen( $this->value ); $i++ )
        {
            $rotate = rand(-15, 15);
 
            $fontSize = rand(28, 36);
            imagettftext($im, $fontSize ,$rotate , 10+$i*31, 50, $black, "impact.ttf",$this->value[$i] ); 
        }
 
 
 
 
        for ( $i = 0; $i < 160; $i++ )
        {
                for ( $j = 0; $j  < 60; $j++ )
                {
                        $pos = rand( 0, 7 );
 
                        if ( imagecolorat( $im, $i, $j ) == $black )
                        {
                                $pos = rand( 6, 7 );
 
 
 
                                imagesetpixel( $im, $i, $j, $bgColors[$pos] );
                        }
                        else
                        {
                                imagesetpixel( $im, $i, $j, $bgColors[$pos] );
                        }
                }
        }
 
        imagejpeg( $im, "images/".$this->image_name.".jpg" );
        imagedestroy( $im );
        echo" <img src='/images/".$this->image_name.".jpg' style='border: 1px solid #000;' width='160' >";
    }
}

The random string/number generator functions are static, so that they can be used anytime.

The string to be shown is stored in the class member value, this is to be set manually using setValue( $value ).

Function showImage renders and shows the image. It uses the 3 base colors Red Green and Blue ( $channel ) to generate the background color. This can be set as a parameter so images get only green ( $channel = 2 ) background, this my be important to exclude variations that are hard to read.

The logic is the following:

In the action you use to render the template where the CAPCTHA is to be shown, generate a value for it ( you can use the createString or createNumber functions ). Flash this value in the action ( $this->setFlash( 'captcha', $this->value ), and "pass" it to the template ( set the value as a member of the action $this->value = $value ).

In the template create an instance of class Captcha. Set the value by using the setValue function. And call showImage().

Create an input field on the template, and override the validate() function in your action.class.php. The logic is simple we have two strings and we want to know if they match or not. So we make an insatnce of confirm validaor, set the check parameter to the original captcha value ( $this->getFlash( 'captcha' ) ) and execute the validator on the input field's post value ( $this->getRequestParameter('name_of_input_field' ) ).

Many of the parameters that are actually fixed in the code should be members of the class and should have proper set/get functions. I've played with this for a short period of time, so feel free to complement the code.

by Kormany Gabor on 2007-06-30, tagged captcha  validation 

Simple Captcha with GD

Ever wanted to have a captcha image verification, but didn't want to go through the trouble of using the jgraph lib? Me too! Here's what I came up with.

sfCaptcha.class.php in /lib

class sfCaptcha 
{
 
  public $securityCode;
  private $codeLength=6;
  private $imageFile= 'captchaImg.jpg';
  public $fontSize  = 12;           
  public $fontColor  = array("252525","8b8787","550707");
 
  public function simpleRandString($length, $list="23456789ABDEFGHJKLMNQRTYabdefghijkmnqrty") {
    /*
     * Generates a random string with the specified length
     * Chars are chosen from the provided [optional] list
    */
    mt_srand((double)microtime()*1000000);
 
    $newstring = "";
 
    if ($length > 0) {
        while (strlen($newstring) < $length) {
            $newstring .= $list[mt_rand(0, strlen($list)-1)];
        }
    }
    return $newstring;
  }
 
  public function generateImage()
  {
 
    $this->securityCode = $this->simpleRandString($this->codeLength);
 
    $img_path = dirname(__FILE__)."/../web/uploads/";
 
    if(!is_writable($img_path) && !is_dir($img_path)){
      $error = "The image path $img_path does not appear to be writable or the folder does not exist. Please verify your settings";
      throw new Exception($error);
    }
 
    $this->img = ImageCreateFromJpeg($img_path.$this->imageFile);
 
    $img_size = getimagesize($img_path.$this->imageFile);
 
    foreach($this->fontColor as $fcolor)
    {
        $color[] = imagecolorallocate($this->img,
                hexdec(substr($fcolor, 1, 2)),
                hexdec(substr($fcolor, 3, 2)), 
                hexdec(substr($fcolor, 5, 2))
                );
    }
    $line = imagecolorallocate($this->img,255,255,255);
    $line2 = imagecolorallocate($this->img,200,200,200);
 
    $fw = imagefontwidth($this->fontSize)+3;
    $fh = imagefontheight($this->fontSize);
 
    // create a new string with a blank space between each letter so it looks better
    $newstr = "";
    for ($i = 0; $i < strlen($this->securityCode); $i++) {
        $newstr .= $this->securityCode[$i] ." ";
    }
 
    // remove the trailing blank
    $newstr = trim($newstr);
 
    // center the string 
    $x = ($img_size[0] - strlen($newstr) * $fw ) / 2;
 
    $font[0] = 'arial.ttf';
    $font[1] = 'TIMES.ttf';
    $font[2] = 'COURI.ttf';
 
    // create random lines over text
    for($i=0; $i <3;$i++){
        $s_x = rand(40,180);
        $s_y = rand(5,35);
        $e_x = rand(($s_x-50), ($s_x+50));
        $e_y = rand(5,35);
        $c = rand(0, (count($color)-1));
      imageline($this->img, $s_x,$s_y, $e_x,$e_y, $color[$c]);
    }
 
    // random bg ellipses
    imageellipse($this->img, $s_x, $s_y, $e_x, $e_y, $line);
    imageellipse($this->img, $e_x, $e_y, $s_x, $s_y, $line2);
 
    // output each character at a random height and standard horizontal spacing
    for ($i = 0; $i < strlen($newstr); $i++) {
        $hz = mt_rand( 10, $img_size[1] - $fh - 5);
 
        // randomize rotation
        $rotate = rand(-35, 35);
 
        // randomize font size
        $this->fontSize =  rand(14, 18);
 
        // radomize color
        $c = rand(0, (count($color)-1));
 
        // imagechar( $this->img, $this->fontSize, $x + ($fw*$i), $hz, $newstr[$i], $color);
        imagettftext($this->img, $this->fontSize,$rotate , $x + ($fw*$i), $hz + 12, $color[0], $font[$c], $newstr[$i]);
    }
  }
}

in the moduleyou want to use, in my case the user module add the following to your actions.

// replace XXX with the name of the action that is calling the form, like validateRegistration if your action is executeRegistration.
// This function validates the stored captcha against the users input and returns true if they match, or returns an error back to the form if they don't.
 public function validateXXX()
  {
    if($this->getRequest()->getMethod() == sfRequest::POST)
    {
      $captcha = $this->getRequestParameter('captcha');
 
      $session_captcha = $this->getUser()->getAttribute('captcha');
 
      if($captcha != $session_captcha)
      {
        $this->getRequest()->setError('captcha', 'The code you entered did not match the one provided, please try again.');
        return false;
      }
    }
    return true;
  }
 
// action that executes the actual image
public function executeGetImage()
  {
    $this->getResponse()->setContentType('image/jpeg');
    $captcha = new sfCaptcha();
    $captcha->generateImage();
    $this->getUser()->setAttribute('captcha', $captcha->securityCode);
    imagejpeg($captcha->img);
      imageDestroy($captcha->img); 
  }

and the in the view showing the image and form

<div class='error'><?php echo form_error('captcha') ?></div>
    <img src='<?php echo url_for('user/getimage'); ?>'><br>
    <?php echo input_tag('captcha') ?>

Note that the image source user/getimage refers to my user module and the executeGetImage() function we added above.

You'll need to add a JPG to your /web/uploads/ directory with the size of 200px w x 40px h and the name "captchaImg.jpg" (you can change the name in the sfCaptcha.classs.php file too). This is used to generate the captcha image and if you choose so you can create a background in the image that will be used. Otherwise, just leave it blank.

by Jason Ibele on 2006-06-13, tagged captcha  image  verification 
(15 comments)