zf2提供了图片验证码Zend\Captcha\Image和符号字符验证码Zend\Captcha\Figlet,图片验证码是网站应用中见得比较多的一种验证码,本文以图片验证码为例。
如果用session来临时保存生成的验证码,就需要先配置session。
session的参数配置:
// /config/autoload/local.php
return array(
'session' => array(
'config' => array(
'class' => 'Zend\Session\Config\SessionConfig',
'options' => array(
'name' => 'zf2ttttt',
),
),
'storage' => 'Zend\Session\Storage\SessionArrayStorage',
'validators' => array(
'Zend\Session\Validator\RemoteAddr',
'Zend\Session\Validator\HttpUserAgent',
),
),
);
Application启动后调用session_start:
// /module/Application/Module.php
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Session\SessionManager;
use Zend\Session\Container;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
//为表单验证对象设置默认的语言翻译器,以便验证码验证不通过时用默认语言提示用户
\Zend\Validator\AbstractValidator::setDefaultTranslator($e->getApplication()->getServiceManager()->get('translator'));
//启动session
$this->bootstrapSession($e);
}
public function bootstrapSession($e){
$session = $e->getApplication()->getServiceManager()->get('Zend\Session\SessionManager');
$session->start();
}
//SessionManager工厂
public function getServiceConfig() {
return array(
'factories' => array(
'Zend\Session\SessionManager' => function ($sm) {
$config = $sm->get('config');
if (isset($config['session'])){
$session = $config['session'];
$sessionConfig = null;
if (isset($session['config'])){
$class = isset($session['config']['class']) ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
$options = isset($session['config']['options']) ? $session['config']['options'] : array();
$sessionConfig = new $class;
$sessionConfig->setOptions($options);
}
$sessionStorage = null;
if (isset($session['storage'])){
$class = $session['storage'];
$sessionStorage = new $class;
}
$sessionSaveHandler = null;
if (isset($session['save_handler'])){
$sessionSaveHandler = $sm->get($session['save_handler']);
}
$sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
} else {
$sessionManager = new SessionManager();
}
Container::setDefaultManager($sessionManager);
return $sessionManager;
},
),
);
}
}
表单Form中添加验证码输入:验证码就是一张图片,可以在表单中用一个text让用户输入验证码,text旁显示验证码图片:
// /module/Test/src/Test/Form/TestForm.php
namespace Test\Form;
......
use Test\Form\MyImgCaptchaValidator;//自定义的验证码检验类
class TestForm extends Form implements InputFilterProviderInterface{
......
public function __construct($name = null) {
......
//添加验证码输入框
$this->add(array(
'name' => 'cv',
'type' => 'Text',
'options' => array(
'label' => '请输入检验码:',
),
'attributes' => array(
'size' => 20,
'maxlength' => 4,
),
));
......
}
public function getInputFilterSpecification() {
......
//自定义的验证码检验对象
$captchaValidator = new MyImgCaptchaValidator();
......
return array(
......
'cv' => array(
'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
array('name' => 'StringToLower'),
),
'validators' => array(
array('name' => 'NotEmpty'),
array(
'name' => 'StringLength',//本例将验证码长度限制为4字符
'options' => array(
'encoding' => 'UTF-8',
'min' => 4,
'max' => 4,
),
),
$captchaValidator,
),
),
);
}
}
自定义的验证码验证类:
// /module/Test/src/Test/Form/MyImgCaptchaValidator.php
namespace Test\Form;
use Zend\Validator\AbstractValidator;
use Zend\Session\Storage\SessionArrayStorage;
class MyImgCaptchaValidator extends AbstractValidator {
const DIFFERENT = 'different';
protected $messageTemplates = array(
self::DIFFERENT => "Capthca inputted is different !",//此处为字符串的key,如果语言文件配置了该字符串,并且为validator设置了默认的tranlaotr,validator基类会自动翻译该字符串
);
public function isValid($value) {
$this->setValue($value);
$isValid = true;
$sessionKey_Capthca = 'sesscaptcha';
$sessionStorage = new SessionArrayStorage();
$captchaWord = $sessionStorage->offsetGet($sessionKey_Capthca);//获取session临时保存的验证码
$wd = $captchaWord;
if ($wd != $value){//比较输入的验证码和生成的验证码
$this->error(self::DIFFERENT);//输入不正确,则设置错误消息
$isValid = false;
}
return $isValid;
}
}
在视图中输出验证码输入框和验证码图片:
// /module/Test/src/view/test/test/testform.phtml
echo '';
$captcha = $this->tform->get('cv');//获取验证码输入框表单元素
echo $formLabel->openTag().$captcha->getOption('label');
echo $this->formInput($captcha);//显示验证码输入框
echo '';//显示验证码图片,$imgSrc为控制器传过来
echo $this->formElementErrors($captcha);//显示错误消息
echo $formLabel->closeTag();
echo '
控制器代码:
// /module/Test/src/Test/Controller/TestController.php
namespace Test\Controller;
use Zend\Captcha\Image;
use Zend\Session\Storage\SessionArrayStorage;
class TestController extends AbstractActionController {
public function testformAction() {
......
if ($this->getRequest()->isPost()){//用户提交了表单,处理表单数据
$postData = array_merge_recursive(
$this->getRequest()->getPost()->toArray(),
$this->getRequest()->getFiles()->toArray()
);
$form->setData($postData);
if ($form->isValid()) {//表单检验成功
.....
}
......
}
//session
$sessionStorage = new SessionArrayStorage();
//创建验证码
$sessionKey_Capthca = 'sesscaptcha';
$icv = new \Zend\Captcha\Image();//zf2只支持生成*.png格式图片
$icv->setFont('public/fonts/arial.ttf');//指定字体文件,可以从windows系统文件夹"WINDOWS\Fonts"下拷贝一个“arial.ttf”文件到/public/fonts目录下
$icv->setFontSize(14);
$icv->setHeight(30);
$icv->setWidth(80);
$icv->setDotNoiseLevel(20);//添加像素点的干扰,默认值100
$icv->setLineNoiseLevel(2);//添加像素线的干扰,默认值5
$icv->setImgDir('public/captcha/'); //特别需要注意的是,imgDir和imgUrl这2个参数,如果设置不当,很容易出现无法创建图片文件或者无法显示图片文件的问题。
//下面对这2个参数的设置和默认值做了以下整理:
//imgDir:默认值是public/images/captcha。
//imgUrl:默认值是/images/capthca。
//可见,默认值是按照网站把/public设置为web根目录来定的。
//setImgDir:如果是以根目录符"/"开头,则认为是绝对路径,例如,setImgDir('/public/captcha/');则图片保存路径为/public/capthca/asdfas.png;
// 如果不是以根目录符"/"开头,则以网站根目录为根,设置的值为网站根目录下的子目录,例如,setImgDir('public/captcha/');则图片保存路径为WebRoot/public/capthca/asdfas.png(WebRoot为网站web根目录);
//setImgUrl:如果是以根目录符"/"开头,则以网站根目录为根,例如,setImgUrl('/public/captcha/');则图片URL为http://xxxx/public/capthca/asdfas.png;
// 如果不是以根目录符"/"开头,则以当前route为为根,例如,假设当前表单URL为http://x/test/testform,那么调用setImgUrl('public/captcha/');则图片URL为http://x/test/public/capthca/asdfas.png;
//综上所述,正确的设置这2个参数的方法是,setImgDir的参数“不要”以“/”开头,setImgUrl的参数“要”以“/”开头。
$icv->setImgUrl('/public/captcha/');
$icv->setWordlen(4);//设置字符个数,默认是8个字符
//创建新的验证码的值
$icv->generate();
//验证码图片的URL
$imgSrc = $icv->getImgUrl().'/'.$icv->getId().$icv->getSuffix();
//验证码的字符串
$captchaWord = $icv->getWord();
//验证码保存到session
$sessionStorage->offsetSet($sessionKey_Capthca, $captchaWord);
return array(
'tform' => $form,
'imgSrc' => $imgSrc,//将验证码图片的url传给视图
);
}
}
另外,由于自定义验证码验证类使用了一个字符串"Capthca inputted is different !",因此,需要在语言文件中配置一下该字符串的中文信息。
添加语言文件配置:
// /module/Test/config/module.config.php
return array(
......
'translator' => array(
'translation_files' => array(
array(
'type' => 'phparray',
'filename' => __DIR__ . '/../language/my_zh_CN.php',//自己创建的语言文件my_zh_CN.php,保存在/module/Test/language/目录下
),
),
),
......
);
在语言文件中添加字符串:
// /module/Test/language/my_zh_CN.php
return array(
"Capthca inputted is different !" => "验证码输入不正确!"
);
有时候,验证码不看不清楚的时候,可能需要点击刷新。要实现点击刷新的功能,可以对以上代码做一些如下修改。
控制器中生成验证码的部分剪切出来放在一个函数中:
// /module/Test/src/Test/Controller/TestController.php
class TestController extends AbstractActionController {
public function createCaptcha(){
//创建验证码
$sessionKey_Capthca = 'sesscaptcha';
$icv = new \Zend\Captcha\Image();//zf2只支持生成*.png格式图片
$icv->setFont('public/fonts/arial.ttf');//指定字体文件,可以从windows系统文件夹"WINDOWS\Fonts"下拷贝一个“arial.ttf”文件到/public/fonts目录下
$icv->setFontSize(14);
$icv->setHeight(30);
$icv->setWidth(80);
$icv->setDotNoiseLevel(20);//添加像素点的干扰,默认值100
$icv->setLineNoiseLevel(2);//添加像素线的干扰,默认值5
$icv->setImgDir('public/captcha/'); //特别需要注意的是,imgDir和imgUrl这2个参数,如果设置不当,很容易出现无法创建图片文件或者无法显示图片文件的问题。
//下面对这2个参数的设置和默认值做了以下整理:
//imgDir:默认值是public/images/captcha。
//imgUrl:默认值是/images/capthca。
//可见,默认值是按照网站把/public设置为web根目录来定的。
//setImgDir:如果是以根目录符"/"开头,则认为是绝对路径,例如,setImgDir('/public/captcha/');则图片保存路径为/public/capthca/asdfas.png;
// 如果不是以根目录符"/"开头,则以网站根目录为根,设置的值为网站根目录下的子目录,例如,setImgDir('public/captcha/');则图片保存路径为WebRoot/public/capthca/asdfas.png(WebRoot为网站web根目录);
//setImgUrl:如果是以根目录符"/"开头,则以网站根目录为根,例如,setImgUrl('/public/captcha/');则图片URL为http://xxxx/public/capthca/asdfas.png;
// 如果不是以根目录符"/"开头,则以当前route为为根,例如,假设当前表单URL为http://x/test/testform,那么调用setImgUrl('public/captcha/');则图片URL为http://x/test/public/capthca/asdfas.png;
//综上所述,正确的设置这2个参数的方法是,setImgDir的参数“不要”以“/”开头,setImgUrl的参数“要”以“/”开头。
$icv->setImgUrl('/public/captcha/');
$icv->setWordlen(4);//设置字符个数,默认是8个字符
//创建新的验证码的值
$icv->generate();
//验证码图片的URL
$imgSrc = $icv->getImgUrl().'/'.$icv->getId().$icv->getSuffix();
//验证码的字符串
$captchaWord = $icv->getWord();
$sessionStorage = new SessionArrayStorage();
//验证码保存到session
$sessionStorage->offsetSet($sessionKey_Capthca, $captchaWord);
return $imgSrc;
}
}
创建一个刷新验证码图片的控制器Action:
// /module/Test/src/Test/Controller/TestController.php
class TestController extends AbstractActionController {
public function refreshcaptchaAction() {
$imgSrc = $this->createCaptcha();
return new JsonModel(array(
'imgSrc' => $imgSrc
));
}
}
视图中添加刷新验证码按钮:
// /module/Test/view/test/test/testform.phtml
echo '';
$captcha = $this->tform->get('cv');
echo $formLabel->openTag().$captcha->getOption('label');
echo $this->formInput($captcha);
echo '';
echo $this->formElementErrors($captcha);
echo $formLabel->closeTag();
echo '';
echo '
添加刷新验证码图片的客户端脚本:
// /module/Test/view/test/test/testform.phtml