Monday, August 10, 2009

A easy captcha component implentation into cakephp.

First save the code below into a file called captcha.php and put it in your controller components folder

Then very important create a folder called "fonts" in your files which is located in webroot/files/ copy the fonts you want to use inside that folder you can add as many fonts as you like and use only true type fonts but here is a link to the fonts i used. www.getkeywords.co.za/files/fonts.tar.gz

uses('security');

class CaptchaComponent extends Object {

var $length = 6;

var $fontpath;

var $fonts;

var $components = array('Session');

var $controller = array();

var $sessionKey = 'Captcha';

var $case = false;

var $filters = array();

var $imgFormat = "png";

var $bgColor = array(255, 255, 255);

var $stringColor = array(0, 0, 0);


function startup(&$controller) {

if (strtolower($controller->name) == 'app' || (strtolower($controller->name) == 'tests' && Configure::read() > 0)) {
return;
}

$this->controller = $controller;

if (!method_exists($controller, 'captcha')) {

trigger_error(__('Could not find function captcha. Please create a captcha function in Controller::$controller.', true), E_USER_WARNING);
die();

}

$this->fontpath = $this->__getFontPath();

if(is_null($this->__getFonts())) {

trigger_error(__('Could not find any fonts in webroot/files/fonts/ please confirm you have created directory and have uploaded only true type fonts!', true), E_USER_WARNING);
die();

}

}


// Add this to controller action which you want to use captcha
// for and the model that has the capchta variable in.
function protect($model = 'Captcha') {

if(isset($this->controller->data[$model]['captcha']) && !empty($this->controller->data[$model]['captcha'])) {

if($this->__check($this->controller->data[$model]['captcha'])) {

$this->Session->del($this->sessionKey);
unset($this->controller->data[$model]['captcha']);

return true;

} else {

$this->__generate();
$this->Session->setFlash(__('Incorrect image verification please retry!',true));
unset($this->controller->data[$model]['captcha']);

return false;

}

} else {

$this->__generate();
return false;

}
}

// Create a function called captcha in a controller and reference
// the captcha image src in the view to it.
function show() {

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");

$this->fontpath = $this->__getFontPath();

$this->fonts = $this->__getFonts();

$this->__makeCaptcha();

$this->controller->autoRender=false;

} //captcha

function __check($string) {

return ($string === $this->Session->read($this->sessionKey));

}

function __generate($protect = false) {

if(!$protect) {

$protect = !$this->Session->check($this->sessionKey);

}

if ($protect) {

$this->Session->write($this->sessionKey, $this->__stringGen());

}

}

function __getFontPath() {

return WWW_ROOT . 'files' . DS . 'fonts' . DS;

}

function __getFonts() {

$fonts = array();

if ($handle = @opendir($this->fontpath)) {

while (($file = readdir($handle)) !== FALSE) {

$extension = strtolower(substr($file, strlen($file) - 3, 3));

if ($extension == 'ttf') {

$fonts[] = $file;

}

}

closedir($handle);

} else {

return null;

}

if (count($fonts) == 0) {

return null;

} else {

return $fonts;

}

} //getFonts

function __getRandFont() {

return $this->fontpath . $this->fonts[mt_rand(0, count($this->fonts) - 1)];

} //getRandFont


function __stringGen() {

$results = null;
$uppercase = range('A', 'Z');
$numeric = range(0, 9);

$CharPool = array_merge($uppercase, $numeric);

if($this->case) {

$lowercase = range('a', 'z');
$CharPool = array_merge($CharPool, $lowercase);

}

$PoolLength = count($CharPool) - 1;

for ($i = 0; $i < $this->length; $i++) {

$results .= $CharPool[mt_rand(0, $PoolLength)];

}

return $results;

} //StringGen

function __makeCaptcha() {

$this->__generate(true);
$captchaString = $this->Session->read($this->sessionKey);

$imagelength = $this->length * 25 + 16;
$imageheight = 75;

$image = imagecreate($imagelength, $imageheight);

$bgcolor = imagecolorallocate($image, $this->bgColor[0], $this->bgColor[1], $this->bgColor[2]);

$stringcolor = imagecolorallocate($image, $this->stringColor[0], $this->stringColor[1], $this->stringColor[2]);

$this->__signs($image, $this->__getRandFont());

for ($i = 0; $i < strlen($captchaString); $i++) {

imagettftext($image, 25, mt_rand(-15, 15), $i * 25 + 10,
mt_rand(30, 70),
$stringcolor,
$this->__getRandFont(),
$captchaString{$i});

}

if(isset($this->filters['noise']) && is_numeric($this->filters['noise'])) {

$this->__noise($image, $this->filters['noise']);

}

if(isset($this->filters['blur']) && is_numeric($this->filters['blur'])) {

$this->__blur($image, $this->filters['blur']);

}

switch($this->imgFormat) {

case "png" : header('Content-type: image/png');
imagepng($image);
break;

case "jpg" : header('Content-type: image/jpg');
imagejpeg($image);
break;

case "jpeg" : header('Content-type: image/jpg');
imagejpeg($image);
break;

case "gif" : header('Content-type: image/gif');
imagegif($image);
break;

default : header('Content-type: image/png');
imagejpeg($image);
break;

}

imagedestroy($image);

} //MakeCaptcha


/*-----------------------------
* FILTER FOR CAPTCHA
*
*
*------------------------------*/

function __noise(&$image, $runs = 30) {

$w = imagesx($image);
$h = imagesy($image);

for ($n = 0; $n < $runs; $n++) {

for ($i = 1; $i <= $h; $i++) {

$randcolor = imagecolorallocate($image,
mt_rand(0, 255),
mt_rand(0, 255),
mt_rand(0, 255));

imagesetpixel($image,
mt_rand(1, $w),
mt_rand(1, $h),
$randcolor);

}

}

} //noise

function __signs(&$image, $font, $cells = 3) {

$w = imagesx($image);
$h = imagesy($image);

for ($i = 0; $i < $cells; $i++) {

$centerX = mt_rand(1, $w);
$centerY = mt_rand(1, $h);
$amount = mt_rand(1, 15);
$stringcolor = imagecolorallocate($image, 175, 175, 175);

for ($n = 0; $n < $amount; $n++) {

$signs = range('A', 'Z');
$sign = $signs[mt_rand(0, count($signs) - 1)];

imagettftext($image, 25,
mt_rand(-15, 15),
$centerX + mt_rand(-50, 50),
$centerY + mt_rand(-50, 50),
$stringcolor, $font, $sign);

}

}

} //signs

function __blur(&$image, $radius = 3) {

$radius = round(max(0, min($radius, 50)) * 2);

$w = imagesx($image);
$h = imagesy($image);

$imgBlur = imagecreate($w, $h);

for ($i = 0; $i < $radius; $i++) {

imagecopy ($imgBlur, $image, 0, 0, 1, 1, $w - 1, $h - 1);
imagecopymerge($imgBlur, $image, 1, 1, 0, 0, $w, $h, 50.0000);
imagecopymerge($imgBlur, $image, 0, 1, 1, 0, $w - 1, $h, 33.3333);
imagecopymerge($imgBlur, $image, 1, 0, 0, 1, $w, $h - 1, 25.0000);
imagecopymerge($imgBlur, $image, 0, 0, 1, 0, $w - 1, $h, 33.3333);
imagecopymerge($imgBlur, $image, 1, 0, 0, 0, $w, $h, 25.0000);
imagecopymerge($imgBlur, $image, 0, 0, 0, 1, $w, $h - 1, 20.0000);
imagecopymerge($imgBlur, $image, 0, 1, 0, 0, $w, $h, 16.6667);
imagecopymerge($imgBlur, $image, 0, 0, 0, 0, $w, $h, 50.0000);
imagecopy ($image , $imgBlur, 0, 0, 0, 0, $w, $h);

}

imagedestroy($imgBlur);

} //blur

} //class: captcha

?>
Then create a helper called captcha.php and put it in your helpers folder.
Helper Class:
/******************************************************************

Projectname: CAPTCHA Helper class
Version: 1.0
Author: Michael James (mikeyjsa@gmail.com)
Website: http://www.getkeywords.co.za
Last modified: 11. June 2008

* GNU General Public License (Version 2, June 1991)
*
* This program is free software; you can redistribute
* it and/or modify it under the terms of the GNU
* General Public License as published by the Free
* Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License
* for more details.

Description:
This helper is used to generate CAPTCHAs.

******************************************************************/
class CaptchaHelper extends AppHelper {

var $helpers = array('html', 'form');

function input($controller = null) {

if(is_null($controller)) {
$controller = $this->params['controller'];
}

$output = array();
$output[] = $this->html->image('/' . $controller . '/captcha/image.png', array('id' => 'captcha_image'));
$output[] = $this->form->input('Captcha/captcha', array('div' => 'captcha_input', 'label' => '(Case Sensitive!)'));

return implode("\r\n", $output);

}

}
?>

First in the controller you want to implement it into add the component then create a function called captcha and and in the following and on the form you want to protect where it checks if the data is empty just add "&& $this->Captcha->protect()". That will return a boolean back.






var $components = array('Captcha');
var $helpers = array('Captcha');

function captcha() {

$this->Captcha->show();

}

function add() {
if (!empty($this->data) && $this->Captcha->protect()) {
$this->ModelName->save($this->data);
}
}


?>
View Template:
Input this code in your .ctp file where you need a captcha

echo $captcha->input();

No comments:

Post a Comment