Yii Framework 验证码,如何生成中文验证码。


在Yii 中生成一个验证码是非常方便的事情我们只需要在页面上直接输出

$this->widget('CCaptcha',array('showRefreshButton'=>false,'clickableImage'=>true,'imageOptions'=>array('alt'=>'点击换图','title'=>'点击换图','style'=>'cursor:pointer')));
在controller中增加

        

public function actions() {

        return array(
            'captcha' => array(
                'class' => 'CaptchaAction',
                'backColor' => 0xFFFFFF,
                'maxLength' => 6,
                'minLength' => 6,
                'transparent' => true,
                'width' => 160,
                'height' => 40,
                'chinese' => true
            )
        );
    }

这样在页面上就输出了一个验证码。在actions 中我们定一个acptcha 一个action 这个action 使用了一些参数,我们来看下这些参数都代表什么意思。

class 图片生成类

backColor 背景颜色

maxLength 最大长度

minLength 最小长度

transparent 是否启用透明

width 宽度

height 高度


chinese 中文

我特意把最后一项加粗,放到最后写,因为这个属性在Yii 框架中是不存在的。这个是我自定义的属性,通过设置Chinese为true 来控制验证码图片是否显示中文。

接下来我们就来看下中文是如何被显示出来的

我们通过阅读Yii 的源代码发现

class CCaptchaAction extends CAction
Yii 是通过这个类来实现验证码程序的,那么我们只需要通过继承CCaptchaAction 来重写里边生成验证码的方法就可以显示中文了。

class CaptchaAction extends CCaptchaAction
我们定义自己的类,继承上边的系统类


protected function generateVerifyCode()
    {

        if($this -> chinese)
        {
            $code = ValidateCode :: model() -> GetRandCode();
            return $code;
        }
        else
        {
            parent::generateVerifyCode();
        } 
     }

我们只需要在生成code的地方返回中文字符就可以了。

到这时候我们的工作应该做完了,可是为什么我们生成的中文是乱码呢?(当然是因为字体不对了)

我们还需要重写系统类中输出验证码的地方,来确保我们生成的中文可以被正确显示。


protected function renderImage($code)
    {

        if($this -> chinese)
        {

            if($this -> backend === null && CCaptcha :: checkRequirements('imagick') || $this -> backend === 'imagick')
                $this -> renderImageImagick($code);
            else if($this -> backend === null && CCaptcha :: checkRequirements('gd') || $this -> backend === 'gd')
                $this -> renderImageGD($code);
        }
        else
        {

            if($this -> backend === null && CCaptcha :: checkRequirements('imagick') || $this -> backend === 'imagick')
                parent :: renderImageImagick($code);
            else if($this -> backend === null && CCaptcha :: checkRequirements('gd') || $this -> backend === 'gd')
                parent :: renderImageGD($code);
        }
    }

    protected function renderImageImagick($code)
    {

        $backColor = new ImagickPixel('#' . dechex($this -> backColor));
        $foreColor = new ImagickPixel('#' . dechex($this -> foreColor));

        $image = new Imagick();
        $image -> newImage($this -> width , $this -> height , $backColor);

        if($this -> fontFile === null)
            $this -> fontFile = dirname(__FILE__) . '/stxingka.ttf';

        $draw = new ImagickDraw();
        $draw -> setFont($this -> fontFile);
        $draw -> setFontSize(30);
        $fontMetrics = $image -> queryFontMetrics($draw , $code);

        $length = strlen($code);
        $w = (int)($fontMetrics['textWidth']) - 8 + $this -> offset * ($length - 1);
        $h = (int)($fontMetrics['textHeight']) - 8;
        $scale = min(($this -> width - $this -> padding * 2) / $w , ($this -> height - $this -> padding * 2) / $h);
        $x = 10;
        $y = round($this -> height * 27 / 40);

        $draw = new ImagickDraw();
        $draw -> setFont($this -> fontFile);
        $draw -> setFontSize((int)(rand(26 , 32) * $scale * 0.8));
        $draw -> setFillColor($foreColor);
        $image -> annotateImage($draw , $x , $y , rand(-10 , 10) , $code);
        $fontMetrics = $image -> queryFontMetrics($draw , $code);
        $x += (int)($fontMetrics['textWidth']) + $this -> offset;

        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");
        $image -> setImageFormat('png');
        echo $image;
    }

    protected function renderImageGD($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);

        if($this -> transparent)
            imagecolortransparent($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__) . '/stxingka.ttf';

        $length = strlen($code);
        $box = imagettfbbox(30 , 0 , $this -> fontFile , $code);
        $w = $box[4] - $box[0] + $this -> 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 * 25 / 40);

        $fontSize = (int)(rand(28 , 32) * $scale * 0.8);
        $angle = rand(-10 , 10);
        $box = imagettftext($image , $fontSize , $angle , $x , $y , $foreColor , $this -> fontFile , $code);
        $x = $box[2] + $this -> 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);
    }

我们重写系统类中的验证码输出程序,引入自己的字体文件

$this -> fontFile = dirname(__FILE__) . '/stxingka.ttf';

当然我是使用这个字体文件,你们可以实验不同的字体文件会有不同的效果的。




贴出整个自定义类的完整代码

class CaptchaAction extends CCaptchaAction
{

    public $chinese = false;

    public $testLimit = 8;

    protected function renderImage($code)
    {

        if($this -> chinese)
        {

            if($this -> backend === null && CCaptcha :: checkRequirements('imagick') || $this -> backend === 'imagick')
                $this -> renderImageImagick($code);
            else if($this -> backend === null && CCaptcha :: checkRequirements('gd') || $this -> backend === 'gd')
                $this -> renderImageGD($code);
        }
        else
        {

            if($this -> backend === null && CCaptcha :: checkRequirements('imagick') || $this -> backend === 'imagick')
                parent :: renderImageImagick($code);
            else if($this -> backend === null && CCaptcha :: checkRequirements('gd') || $this -> backend === 'gd')
                parent :: renderImageGD($code);
        }
    }

    protected function renderImageImagick($code)
    {

        $backColor = new ImagickPixel('#' . dechex($this -> backColor));
        $foreColor = new ImagickPixel('#' . dechex($this -> foreColor));

        $image = new Imagick();
        $image -> newImage($this -> width , $this -> height , $backColor);

        if($this -> fontFile === null)
            $this -> fontFile = dirname(__FILE__) . '/stxingka.ttf';

        $draw = new ImagickDraw();
        $draw -> setFont($this -> fontFile);
        $draw -> setFontSize(30);
        $fontMetrics = $image -> queryFontMetrics($draw , $code);

        $length = strlen($code);
        $w = (int)($fontMetrics['textWidth']) - 8 + $this -> offset * ($length - 1);
        $h = (int)($fontMetrics['textHeight']) - 8;
        $scale = min(($this -> width - $this -> padding * 2) / $w , ($this -> height - $this -> padding * 2) / $h);
        $x = 10;
        $y = round($this -> height * 27 / 40);

        $draw = new ImagickDraw();
        $draw -> setFont($this -> fontFile);
        $draw -> setFontSize((int)(rand(26 , 32) * $scale * 0.8));
        $draw -> setFillColor($foreColor);
        $image -> annotateImage($draw , $x , $y , rand(-10 , 10) , $code);
        $fontMetrics = $image -> queryFontMetrics($draw , $code);
        $x += (int)($fontMetrics['textWidth']) + $this -> offset;

        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");
        $image -> setImageFormat('png');
        echo $image;
    }

    protected function renderImageGD($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);

        if($this -> transparent)
            imagecolortransparent($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__) . '/stxingka.ttf';

        $length = strlen($code);
        $box = imagettfbbox(30 , 0 , $this -> fontFile , $code);
        $w = $box[4] - $box[0] + $this -> 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 * 25 / 40);

        $fontSize = (int)(rand(28 , 32) * $scale * 0.8);
        $angle = rand(-10 , 10);
        $box = imagettftext($image , $fontSize , $angle , $x , $y , $foreColor , $this -> fontFile , $code);
        $x = $box[2] + $this -> 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);
    }

    protected function generateVerifyCode()
    {

        if($this -> chinese)
        {
            $code = ValidateCode :: model() -> GetRandCode();
            return $code;
        }
        else
        {
            parent::generateVerifyCode();
        } 
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值