![]() |
|
Snippets |
|
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.
Comments on this snippet
Hi everybody, I needed to add return sfView::NONE; to the action to get everything perfectly working. Bye!
There is one other change to be made. Each of the hexdec() that appear when allocation colors should be like this: hexdec(substr($fcolor, 0, 2)) hexdec(substr($fcolor, 2, 2)) hexdec(substr($fcolor, 4, 2)) and not 1,3,5 as was written!
See ya!
i still getting Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/sfproject/lib/sfCaptcha.class.php on line 103 anyone gets this problem?
I think the validateXXX() method has some problems: - If user does not request actionGetImage and enters nothing in the 'captcha' field, he always passes the validateXXX() method - If user enters correct captcha code once and does not request actionGetImage anymore, he always passes the validateXXX() method later
and this is my solution
public function validateXXX() { if($this->getRequest()->getMethod() == sfRequest::POST) { $captcha = $this->getRequestParameter('captcha');
}
public function validateXXX() { if($this->getRequest()->getMethod() == sfRequest::POST) { $captcha = $this->getRequestParameter('captcha');
}
sorry all, i dont know why the code become that. I cant edit my post
Once past validation you need to unset 'captcha' session variable. This, among other things, will prevent user from refreshing the form and resubmitting the same form values.
in myCaptchaValidator class:
in validateAction() method:
[quote] i still getting Warning: imagettftext() [function.imagettftext]: Could not find/open font in /home/sfproject/lib/sfCaptcha.class.php on line 103 anyone gets this problem? [/quote]
You're are getting this warning because GD can't find the fonts declared. YOu must provide a path to where the fonts can be found.
just change
to
--
An Vu, you should always include the GetImage action when you want to use the Captcha verification, so I don't see your point in users bypassing verification when getImage isn't called. You, the programmer, add it to the page, the user can't avoid it if it's in the page. The reason for not emptying the stored Captcha after completing was so that you can write redirect functions to avoid people skip[ping the Captch page altogether. If you don't have a stored, and verified captcha, redirect them back to the Captcha page and force them to verify.
You are of course free to use it how you want, but this was the reasoning behind it.
My response to the first part about font got cut off, it should have read...
just change
to
For captcha validation the Validator might be :
the validation yaml is:
captcha: required: msg: Recopier le texte de l'image sfCaptchaValidator: captcha_error: Recopier le texte de l'imageAlso I had trouble havinf the captche image to display correctly in my apps it happens that changing the action code to :
replacing the imagejpeg/sfView::NONE code by the renderText has an effect for me ... hope this help. Benoit
Even the return $this->renderText(imagejpeg($captcha->img)); didn't work for me. I had to do it like this:
Doing it this way you can also cleanup the image again!
so the ValidateXXX method goes inside of the action class?...
can someone help me out...when i follow the instructions directly on the form i do not get an image...
when i try to call the module/action directly...i get this...
class sfCaptcha { public $securityCode; private $codeLength=6; private $imageFile= '/home/sfprojects/isports/web/uploads/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] = '/home/sfprojects/isports/web/fonts/ohw.ttf'; $font[1] = '/home/sfprojects/isports/web/fonts/scr.ttf'; $font[2] = '/home/sfprojects/isports/web/fonts/sg.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]); } } } Fatal error: Class 'sfCaptcha' not found in /home/sfprojects/isports/apps/frontend/modules/register/actions/actions.class.php on line 122
i've already cleared the cache...