首页 > 代码库 > ZendFramework2学习笔记 验证码

ZendFramework2学习笔记 验证码

    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 '<div>';

$captcha = $this->tform->get('cv');//获取验证码输入框表单元素

echo $formLabel->openTag().$captcha->getOption('label');

echo $this->formInput($captcha);//显示验证码输入框

echo '<img src=http://www.mamicode.com/"'.$imgSrc.'">
';//显示验证码图片,$imgSrc为控制器传过来>

    控制器代码:

// /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 = http://www.mamicode.com/array_merge_recursive(>

    另外,由于自定义验证码验证类使用了一个字符串"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 = http://www.mamicode.com/$icv->getImgUrl().'/'.$icv->getId().$icv->getSuffix();>

    创建一个刷新验证码图片的控制器Action:

// /module/Test/src/Test/Controller/TestController.php

class TestController extends AbstractActionController {

     public function refreshcaptchaAction() {
         $imgSrc = http://www.mamicode.com/$this->createCaptcha();>

    视图中添加刷新验证码按钮:

// /module/Test/view/test/test/testform.phtml

echo '<div>';
$captcha = $this->tform->get('cv');
echo $formLabel->openTag().$captcha->getOption('label');
echo $this->formInput($captcha);
echo '<img id=imgcaptcha src="'.$imgSrc.'"></div>';
echo $this->formElementErrors($captcha);
echo $formLabel->closeTag();

echo '<input type="button" value="刷新" onclick="javascript:refreshCaptcha();"/>';

echo '</div>';

    添加刷新验证码图片的客户端脚本:

// /module/Test/view/test/test/testform.phtml

<script>
    
function refreshCaptcha(){
    var ul = '/test/refreshcaptcha';
    //alert(ul);
    
    $.ajax({
        type : "GET",
        url : ul,
        dataType : "json",
        success : function(data, textStatus) {
            		$("#imgcaptcha").attr("src",data.imgSrc);          
                    },
        error : function(r, t, r){
                        
                    }
    });
}

</script>














ZendFramework2学习笔记 验证码