PHP模块之验证码

蓝咒 提交于 2020-04-29 23:20:14

1.前言

验证码的实现是当前网站必备的技术栈,那么验证码究竟是怎么实现的呢?让我们一起揭开它的神秘面纱。

代码分享:https://github.com/mtdgclub/libraryClass

详见Captcha.class.php

2.验证码模块的实现

2.1实现步骤

  • 创建底图并填充
  • 创建验证码
  • 绘制验证码
  • 添加干扰元素
  • 输出/保存/销毁图片

2.2创建底图并填充

//通过该函数创建底图
$image = imagecreatetruecolor(100, 30);
//#FFFFFFFFFFFF,做个白色填充
$bgcolor = imagecolorallocate($image, 255, 255, 255);

//填充到底图中
imagefill($image, 0, 0, $bgcolor);

PS:imagecreatetruecolor默认输出是黑色的背景可通过 imagecolorallocate()函数生成一块填充图,再通过imagefill给背景填充颜色。

2.3创建验证码

/**
 *生成验证码字符
 * @param int $lenght 验证按字符长度
 * @return bool|string
 */
private function _generateStr($lenght = 4)
{
    if ($lenght < 1 || $lenght > 30) {
        return false;
    }
    $chars = array(
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'i', 's', 't', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'M', 'N', 'P', 'Q', 'I', 'S', 'T', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9'
    );

//array_flip() 函数用于反转/交换数组中的键名和对应关联的键值
//array_rand() 函数返回一个包含随机键名的数组
    $str = join('', array_rand(array_flip($chars), $lenght));
    return $str;
}

2.4绘制验证码

//绘制验证码
for ($i = 0; $i < $this->_lenght; $i++) {
    $size = $this->_size;
    $angle = mt_rand(-30, 30);
    $x = ceil($this->_width / $this->_lenght) * $i * mt_rand(5, 10);
    $y = ceil($this->_height / 1.5);
    //定义字体颜色
    $color = $this->$this->_getRandColor();
    $fontfile = $this->_fontfile;
    $text = mb_substr($str, $i, 1, 'utf-8');
    //在范围内随机定义坐标
    //imagestring($this->_image, $size, $x, $y, $text, $color);
    //使用指定的字体文件绘制文字
    imagettftext($this->_image, $size, $angle, $x, $y, $color, $fontfile, $text);
}

PS:imageString()这个函数并不支持汉字的绘制;但是mageTtfText()函数函数能绘制UTF-8编码的字符串。

2.5添加干扰点数

在封装的函数中添加雪花、像素、线段等干扰元素

//判断是否调用了干扰元素
if ($this->_snow) {
    $this->_getSnow();
} elseif ($this->_pixel) {
    $this->_getPixel();
} elseif ($this->_line) {
    $this->_getLine();
}

2.5.1雪花干扰元素

/**
 * 干扰元素,雪花
 */
private function _getSnow()
{
    for ($i = 1; $i <= $this->_snow; $i++) {
        imagestring($this->_image, mt_rand(1, 5), mt_rand(0, $this->_width), mt_rand(0, $this->_height), '*', $this->_getRandColor());
    }
}

2.5.2像素干扰元素

/**
 * 干扰元素,像素
 */
private function _getPixel()
{
    for ($i = 1; $i <= $this->_pixel; $i++) {
        imagesetpixel($this->_image, mt_rand(0, $this->_width), mt_rand(0, $this->_height), $this->_getRandColor());
    }
}

2.5.3线段干扰元素

/**
 * 干扰元素,横线
 */
private function _getLine()
{
    for ($i = 1; $i <= $this->_line; $i++) {
        imageline($this->_image, mt_rand(0, $this->_width), mt_rand(0, $this->_height), mt_rand(0, $this->_width), mt_rand(0, $this->_height), $this->_getRandColor());
    }
}

2.6输出/保存/销毁图片

输出图片前,必须提前输出header信息声明

//输出图像
header('content-type:image/png');
imagepng($this->_image);
imagedestroy($this->_image);
return strtolower($str);

如果保存验证码图片以及验证码,可考虑下述代码:

//保存图像
$fileName = 'captcha/' . microtime() . '.png';
//检测目录是否存在,不存在则自动创建
$position = strrpos($fileName, '/');
$path = substr($fileName, 0, $position);
//创建目录
if (!file_exists($path)) {
    mkdir($path, 0777, true);
}
//保存图片
$res = file_put_contents($fileName,$this->_image);
if($res != FALSE){
    //todo 存储图片和验证码,可考虑复用
}

3.总结

以上完成了验证码的封装,验证码的实现并不难,但我们设置验证码是为了检验用户的操作是本人操作,所以究其本质就是为了保证操作的安全性,随着网络世界的发展,如何如何维护好系统安全性是个复杂的问题,对于我们而言,验证码就是最常规的验证操作。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!