Подключаем yii капчу к сайту на другом движке
Рубрика: Работаем с капчей (captcha)
6 Апр. 2010Сегодня мы разберем как подключать мою «математическую капчу» на обычный движок php магазина. Название движка я не знаю, да и это не важно, мы просто разберем как вырвать кусок yii и подключать к совершенно не зависимому сайту...
---Я уже писал подобную статью, но из-за некоторых проблем - решил её написать еще раз.
Раньше форма связи на сайте выглядела следующим образом:![]()
- капча с минимальным шумом
- размер шрифта постоянно одинаковый
- кол-ву символов постоянно одинаково
Заказчик попросил сделать что то другое, т.к. спам боты иногда эту капчу всё таки ломали. Недолго думая я решил присобачить «математическую капчу» которую я писал на Yii. Осталось найти классы которые отвечают за её вывод и выдрать их. (согласитесь, что будет лишним переносить весь фреймворка ради вывода капчи на другом движке, проще пару классов забрать с фреймворка)
Всем известно что именно класс CCaptchaAction отвечает за отображение капчи на экране. Именно в нем генерируется число в капче. Вот так класс выглядит в чистом, не тронутом виде:
<?php
/**
* CCaptchaAction class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2009 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CCaptchaAction renders a CAPTCHA image.
*
* CCaptchaAction is used together with {@link CCaptcha} and {@link CCaptchaValidator}
* to provide the {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA} feature.
*
* You must configure properties of CCaptchaAction to customize the appearance of
* the generated image.
*
* Note, CCaptchaAction requires PHP GD2 extension.
*
* Using CAPTCHA involves the following steps:
* <ol>
* <li>Override {@link CController::actions()} and register an action of class CCaptchaAction with ID 'captcha'.</li>
* <li>In the form model, declare an attribute to store user-entered verification code, and declare the attribute
* to be validated by the 'captcha' validator.</li>
* <li>In the controller view, insert a {@link CCaptcha} widget in the form.</li>
* </ol>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id: CCaptchaAction.php 726 2009-02-23 02:20:59Z qiang.xue $
* @package system.web.widgets.captcha
* @since 1.0
*/
class CCaptchaAction extends CAction
{
/**
* The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
*/
const REFRESH_GET_VAR='refresh';
/**
* Prefix to the session variable name used by the action.
*/
const SESSION_VAR_PREFIX='Yii.CCaptchaAction.';
/**
* @var integer how many times should the same CAPTCHA be displayed. Defaults to 3.
*/
public $testLimit=3;
/**
* @var integer the width of the generated CAPTCHA image. Defaults to 120.
*/
public $width=120;
/**
* @var integer the height of the generated CAPTCHA image. Defaults to 50.
*/
public $height=50;
/**
* @var integer padding around the text. Defaults to 2.
*/
public $padding=2;
/**
* @var integer the background color. For example, 0x55FF00.
* Defaults to 0xFFFFFF, meaning white color.
*/
public $backColor=0xFFFFFF;
/**
* @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color).
*/
public $foreColor=0x2040A0;
/**
* @var integer the minimum length for randomly generated word. Defaults to 6.
*/
public $minLength=6;
/**
* @var integer the maximum length for randomly generated word. Defaults to 7.
*/
public $maxLength=7;
/**
* @var string the TrueType font file. Defaults to Duality.ttf which is provided
* with the Yii release.
*/
public $fontFile;
/**
* Runs the action.
* If the GET parameter {@link wsdlVar} exists, the action will serve WSDL content;
* If not, the action will handle the remote method invocation.
*/
public function run()
{
if(isset($_GET[self::REFRESH_GET_VAR])) // AJAX request for regenerating code
{
$code=$this->getVerifyCode(true);
// we add a random 'v' parameter so that FireFox can refresh the image
// when src attribute of image tag is changed
echo $this->getController()->createUrl($this->getId(),array('v'=>rand(0,10000)));
}
else
{
$session=Yii::app()->session;
$session->open();
$name=$this->getSessionKey().'count';
if($session[$name]===null || $session[$name]>=$this->testLimit)
$regenerate=true;
else
{
$session[$name]=$session[$name]+1;
$regenerate=false;
}
$this->renderImage($this->getVerifyCode($regenerate));
Yii::app()->end();
}
}
/**
* Gets the verification code.
* @param string whether the verification code should be regenerated.
* @return string the verification code.
*/
public function getVerifyCode($regenerate=false)
{
$session=Yii::app()->session;
$session->open();
$name=$this->getSessionKey();
if($session[$name]===null || $regenerate)
{
$session[$name]=$this->generateVerifyCode();
$session[$name.'count']=1;
}
return $session[$name];
}
/**
* Validates the input to see if it matches the generated code.
* @param string user input
* @param boolean whether the comparison should be case-sensitive
* @return whether the input is valid
*/
public function validate($input,$caseSensitive)
{
$code=$this->getVerifyCode();
return $caseSensitive?($input===$code):!strcasecmp($input,$code);
}
/**
* Generates a new verification code.
* @return string the generated verification code
*/
protected function generateVerifyCode()
{
if($this->minLength<3)
$this->minLength=3;
if($this->maxLength>20)
$this->maxLength=20;
if($this->minLength>$this->maxLength)
$this->maxLength=$this->minLength;
$length=rand($this->minLength,$this->maxLength);
$letters='bcdfghjklmnpqrstvwxyz';
$vowels='aeiou';
$code='';
for($i=0;$i<$length;++$i)
{
if($i%2 && rand(0,10)>2 || !($i%2) && rand(0,10)>9)
$code.=$vowels[rand(0,4)];
else
$code.=$letters[rand(0,20)];
}
return $code;
}
/**
* Returns the session variable name used to store verification code.
* @return string the session variable name
*/
protected function getSessionKey()
{
return self::SESSION_VAR_PREFIX.Yii::app()->getId().'.'.$this->getController()->getUniqueId().'.'.$this->getId();
}
/**
* Renders the CAPTCHA image based on the code.
* @param string the verification code
* @return string image content
*/
protected function renderImage($code)
{
$image=imagecreatetruecolor($this->width,$this->height);
$backColor=imagecolorallocate($image,
(int)($this->backColor%0x1000000/0x10000),
(int)($this->backColor%0x10000/0x100),
$this->backColor%0x100);
imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor);
imagecolordeallocate($image,$backColor);
$foreColor=imagecolorallocate($image,
(int)($this->foreColor%0x1000000/0x10000),
(int)($this->foreColor%0x10000/0x100),
$this->foreColor%0x100);
if($this->fontFile===null)
$this->fontFile=dirname(__FILE__).'/Duality.ttf';
$offset=2;
$length=strlen($code);
$box=imagettfbbox(30,0,$this->fontFile,$code);
$w=$box[4]-$box[0]-$offset*($length-1);
$h=$box[1]-$box[5];
$scale=min(($this->width-$this->padding*2)/$w,($this->height-$this->padding*2)/$h);
$x=10;
$y=round($this->height*27/40);
for($i=0;$i<$length;++$i)
{
$fontSize=(int)(rand(26,32)*$scale*0.8);
$angle=rand(-10,10);
$letter=$code[$i];
$box=imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter);
$x=$box[2]-$offset;
}
imagecolordeallocate($image,$foreColor);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
}
}
Как видите там есть много всего ненужного. Я не собераюсь переносить весь yii функционал на этот движок, просто хочу иметь возможность:
- Через minLength и maxLength изменять сложность выражения.
- Через backColor и foreColor изменять цвет фона и букв
- Через fontFile изменять шрифт для капчи
Я убрал наследование от CAction и несколько ненужных (на мой взгляд) методов. Получилось достаточно компактно
<?php
/**
* CCaptchaAction class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2009 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CCaptchaAction renders a CAPTCHA image.
*
* CCaptchaAction is used together with {@link CCaptcha} and {@link CCaptchaValidator}
* to provide the {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA} feature.
*
* You must configure properties of CCaptchaAction to customize the appearance of
* the generated image.
*
* Note, CCaptchaAction requires PHP GD2 extension.
*
* Using CAPTCHA involves the following steps:
* <ol>
* <li>Override {@link CController::actions()} and register an action of class CCaptchaAction with ID 'captcha'.</li>
* <li>In the form model, declare an attribute to store user-entered verification code, and declare the attribute
* to be validated by the 'captcha' validator.</li>
* <li>In the controller view, insert a {@link CCaptcha} widget in the form.</li>
* </ol>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id: CCaptchaAction.php 726 2009-02-23 02:20:59Z qiang.xue $
* @package system.web.widgets.captcha
* @since 1.0
*/
class CCaptchaAction
{
/**
* The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
*/
const REFRESH_GET_VAR='refresh';
/**
* Prefix to the session variable name used by the action.
*/
const SESSION_VAR_PREFIX='Yii.CCaptchaAction.';
/**
* @var integer how many times should the same CAPTCHA be displayed. Defaults to 3.
*/
public $testLimit=1;
/**
* @var integer the width of the generated CAPTCHA image. Defaults to 120.
*/
public $width=200;
/**
* @var integer the height of the generated CAPTCHA image. Defaults to 50.
*/
public $height=75;
/**
* @var integer padding around the text. Defaults to 2.
*/
public $padding=0;
/**
* @var integer the background color. For example, 0x55FF00.
* Defaults to 0xFFFFFF, meaning white color.
*/
public $backColor=0xFFFFFF;
/**
* @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color).
*/
public $foreColor=0x2040A0;
/**
* @var integer the minimum length for randomly generated word. Defaults to 6.
*/
public $minLength=6;
/**
* @var integer the maximum length for randomly generated word. Defaults to 7.
*/
public $maxLength=7;
/**
* @var string the TrueType font file. Defaults to Duality.ttf which is provided
* with the Yii release.
*/
public $fontFile;
public $code;
/**
* Renders the CAPTCHA image based on the code.
* @param string the verification code
* @return string image content
*/
function renderImage()
{
$this->code = $this->generateVerifyCode();
$code = $this->showCode($this->code);
$image=imagecreatetruecolor($this->width,$this->height);
$backColor=imagecolorallocate($image,
(int)($this->backColor%0x1000000/0x10000),
(int)($this->backColor%0x10000/0x100),
$this->backColor%0x100);
imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor);
imagecolordeallocate($image,$backColor);
$foreColor=imagecolorallocate($image,
(int)($this->foreColor%0x1000000/0x10000),
(int)($this->foreColor%0x10000/0x100),
$this->foreColor%0x100);
if($this->fontFile===null)
$this->fontFile=dirname(__FILE__).'/Duality.ttf';
$offset=2;
$length=strlen($code);
$box=imagettfbbox(30,0,$this->fontFile,$code);
$w=$box[4]-$box[0]-$offset*($length-1);
$h=$box[1]-$box[5];
$scale=min(($this->width-$this->padding*2)/$w,($this->height-$this->padding*2)/$h);
$x=10;
$y=round($this->height*27/40);
for($i=0;$i<$length;++$i)
{
$fontSize=(int)(rand(26,32)*$scale*0.8);
$angle=rand(-10,10);
$letter=$code[$i];
$box=imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter);
$x=$box[2]-$offset;
}
imagecolordeallocate($image,$foreColor);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
}
function showCode($code) {
$rand = rand(1, (int)$code-1);
return (rand(0, 1)) ? (int)$code-$rand."+".(int)$rand : (int)$code+$rand."-".(int)$rand;
}
function generateVerifyCode()
{
return rand((int)$this->minLength, (int)$this->maxLength);
}
}
Этот класс я перенес на хост к движку магазина.
Как вы понимаете в самом магазине уже была капча, поэтому механизм валидации и тп — мне писать не пришлось. Старая капча запоминала код в сессию:
$_SESSION['captcha']
после чего уже сверяла введенный в поле код с тем что сохранен. Поэтому в конце своего класса я добавил что б капча сразу рендерилась на экран и сохраняла значение в сессию:
$abc = new CCaptchaAction();
$abc->renderImage();
session_start();
$_SESSION['captcha'] = $abc->code;
В сумме получился вот такой не большой CCaptchaAction:
<?php
/**
* CCaptchaAction class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2009 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CCaptchaAction renders a CAPTCHA image.
*
* CCaptchaAction is used together with {@link CCaptcha} and {@link CCaptchaValidator}
* to provide the {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA} feature.
*
* You must configure properties of CCaptchaAction to customize the appearance of
* the generated image.
*
* Note, CCaptchaAction requires PHP GD2 extension.
*
* Using CAPTCHA involves the following steps:
* <ol>
* <li>Override {@link CController::actions()} and register an action of class CCaptchaAction with ID 'captcha'.</li>
* <li>In the form model, declare an attribute to store user-entered verification code, and declare the attribute
* to be validated by the 'captcha' validator.</li>
* <li>In the controller view, insert a {@link CCaptcha} widget in the form.</li>
* </ol>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id: CCaptchaAction.php 726 2009-02-23 02:20:59Z qiang.xue $
* @package system.web.widgets.captcha
* @since 1.0
*/
class CCaptchaAction
{
/**
* The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
*/
const REFRESH_GET_VAR='refresh';
/**
* Prefix to the session variable name used by the action.
*/
const SESSION_VAR_PREFIX='Yii.CCaptchaAction.';
/**
* @var integer how many times should the same CAPTCHA be displayed. Defaults to 3.
*/
public $testLimit=1;
/**
* @var integer the width of the generated CAPTCHA image. Defaults to 120.
*/
public $width=200;
/**
* @var integer the height of the generated CAPTCHA image. Defaults to 50.
*/
public $height=75;
/**
* @var integer padding around the text. Defaults to 2.
*/
public $padding=0;
/**
* @var integer the background color. For example, 0x55FF00.
* Defaults to 0xFFFFFF, meaning white color.
*/
public $backColor=0xFFFFFF;
/**
* @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color).
*/
public $foreColor=0x2040A0;
/**
* @var integer the minimum length for randomly generated word. Defaults to 6.
*/
public $minLength=6;
/**
* @var integer the maximum length for randomly generated word. Defaults to 7.
*/
public $maxLength=7;
/**
* @var string the TrueType font file. Defaults to Duality.ttf which is provided
* with the Yii release.
*/
public $fontFile;
public $code;
/**
* Renders the CAPTCHA image based on the code.
* @param string the verification code
* @return string image content
*/
function renderImage()
{
$this->code = $this->generateVerifyCode();
$code = $this->showCode($this->code);
$image=imagecreatetruecolor($this->width,$this->height);
$backColor=imagecolorallocate($image,
(int)($this->backColor%0x1000000/0x10000),
(int)($this->backColor%0x10000/0x100),
$this->backColor%0x100);
imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor);
imagecolordeallocate($image,$backColor);
$foreColor=imagecolorallocate($image,
(int)($this->foreColor%0x1000000/0x10000),
(int)($this->foreColor%0x10000/0x100),
$this->foreColor%0x100);
if($this->fontFile===null)
$this->fontFile=dirname(__FILE__).'/Duality.ttf';
$offset=2;
$length=strlen($code);
$box=imagettfbbox(30,0,$this->fontFile,$code);
$w=$box[4]-$box[0]-$offset*($length-1);
$h=$box[1]-$box[5];
$scale=min(($this->width-$this->padding*2)/$w,($this->height-$this->padding*2)/$h);
$x=10;
$y=round($this->height*27/40);
for($i=0;$i<$length;++$i)
{
$fontSize=(int)(rand(26,32)*$scale*0.8);
$angle=rand(-10,10);
$letter=$code[$i];
$box=imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter);
$x=$box[2]-$offset;
}
imagecolordeallocate($image,$foreColor);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
}
function showCode($code) {
$rand = rand(1, (int)$code-1);
return (rand(0, 1)) ? (int)$code-$rand."+".(int)$rand : (int)$code+$rand."-".(int)$rand;
}
function generateVerifyCode()
{
return rand((int)$this->minLength, (int)$this->maxLength);
}
}
$abc = new CCaptchaAction();
$abc->renderImage();
session_start();
$_SESSION['captcha'] = $abc->code;
Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
- Эта статья устарела т.к. была написана для yii версии 1.0.х; Если вы используете более новую версию - у вас могут ... "Урок 3 : Первый раз, первый контроллер.."
- Очень часто при общении с клиентами у меня в браузере я вижу одно, а у них почему то всё ... "Clip2Net - лучше один раз показать"
- Давайте сегодня поговорим о составлении древовидной структуры средствами встроенного в Yii класса CTreeView.
next
Сегодня просматривал официальный форум фреймворка и в одном ... "Учимся создавать красивые деревья! (CTreeView)"

[adm] zolter
Было сказано: Вторник, 06 Апрель 2010
Как и обещал, написал снова статью которая удалилась в день пожара


