- 目录
- 1. 前言
- 2. 验证码模块的实现
- 2.1实现步骤
- 2.2创建底图并填充
- 2.3创建验证码
- 2.4绘制验证码
- 2.5添加干扰点数
- 2.5.1雪花干扰元素
- 2.5.2像素干扰元素
- 2.5.3线段干扰元素
- 2.6输出/保存/销毁图片
- 3. 总结
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.总结
以上完成了验证码的封装,验证码的实现并不难,但我们设置验证码是为了检验用户的操作是本人操作,所以究其本质就是为了保证操作的安全性,随着网络世界的发展,如何如何维护好系统安全性是个复杂的问题,对于我们而言,验证码就是最常规的验证操作。
来源:oschina
链接:https://my.oschina.net/mtdg/blog/4258713