PHP算式验证码和汉字验证码的实现方法

在PHP网站开发中,验证码可以有效地保护我们的表单不被恶意提交,但是如果不使用算式验证码或者汉字验证码,仅仅使用简单的字母或者数字验证码,这样的验证码方案真的安全吗?

  验证码已经是现在网站中非常基础的知识点了,验证码的存在可以防止恶意破解密码、刷票、灌水,可以有效的防止暴力破解特定用户。

验证码,大家都不陌生。

大家知道简单数字或者字母验证码很容易被破解,但是算式验证码或者中文汉字验证码不容易被破解,所以建议大家在使用验证码的时候,尽量用算式验证码或者中文汉字验证码。

  现在就来了解了解那些年PHP中屌屌的验证码吧。

验证码存在的目的是什么?尽可能的区别出人或机器人的操作,换种说法也就是阻止机器人去系统的破坏。比如机器人发贴、注册、广告等等批量行为,对系统的平衡都有一个破坏。

下面是我写的两种验证码代码,有用到的朋友可以参考下:

  首先,以四位验证码为例(多位验证码一样的道理)。

第一阶段:入门型

1.算式验证码:

  目前网站大多仍然采用静态图片验证码,因为这样实现起来简单又方便,不需要过硬的功底,当然这也是基础。而其原理也就是通过PHP的画图功能将文字画成图片返回到页面。因此,我们解决的问题也就只有三步而已:

早期验证码就不说了,比如纯数字型的、纯字母型的、字母加数字型、字母数字加特殊符号的,稍复杂点的就是在上述基础上加一些斜线、改变一下粗细、颜色、干扰像素等,但对于真正的识别技术来说,这些都不是太大问题。如下图所示:

<?php
session_start();
header("Content-type: image/png");
$num1 = mt_rand(0,9);//第一位数
$num2 = mt_rand(1,9);//第二位数
$type_str = "+-*";//方法字符串集合
$type = substr($type_str,rand(0,2),1);//随机方法
$change = mt_rand(1,3);
if($change==1){
 $code = "$num1$type$num2=?";
 $result = "$verifyCode=$num1$type$num2;";
 eval($result);
 $_SESSION['authnum_session'] = $verifyCode;  
}elseif($change==2){
 $result = "$verifyCode=$num1$type$num2;";
 eval($result);
    $code = $num1.$type."_=".$verifyCode;
 $_SESSION['authnum_session'] = $num2;  
}elseif($change==3){
 $result = "$verifyCode=$num1$type$num2;";
 eval($result);
    $code = "_".$type.$num2."=".$verifyCode;
 $_SESSION['authnum_session'] = $num1;  
}
$im = imagecreate(68,28);   
$black = imagecolorallocate($im, 0,0,0);     
$white = imagecolorallocate($im, 255,255,255);
$gray = imagecolorallocate($im, 200,200,200);
$red = imagecolorallocate($im, 255, 0, 0);
imagefill($im,0,0,$white);        
imagestring($im, 5, 10, 8, $code, $black);    
for($i=0;$i<70;$i++) {
 imagesetpixel($im, mt_rand(0, 58) , mt_rand(0, 28) , $black); 
 imagesetpixel($im, mt_rand(0, 58) , mt_rand(0, 28) , $red); 
 imagesetpixel($im, mt_rand(0, 58) , mt_rand(0, 28) , $gray); 
}
imagepng($im);
imagedestroy($im);
?>
  1. 随机生成验证码的内容
  2. 将验证码转换成图片,即绘图
  3. 将所绘出的图返回到页面中

各种类型的验证码

2.中文汉字验证码:

  当然,PHP默认是没有开启绘图功能的,因此,在php.ini的配置文件中先开启绘图功能吧:搜到 
;extension=php_gd2.dll  将前面的分号去掉即可。(记得保存喔!)

第二阶段:复杂级

<?php
session_start();
$ch_str="的一是在了不和有大这主中人上为们地个用工时要动国产以我到他会作来分生对于学下级就年阶义发成部民可出能方进同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批如应形想制心样干都向变关点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫康遵牧遭幅园腔订香肉弟屋敏恢忘衣孙龄岭骗休借丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩";
$len = mb_strlen($ch_str,"utf-8");//汉字长度
$str = array();
for($i=0;$i<4;$i++){
   $pos = mt_rand(0,$len-5);//开始位置
   $str[] = mb_substr($ch_str,$pos,1,"utf-8");
}
$authnum_session = implode("",$str);
$_SESSION['authnum_session'] = $authnum_session;   //记录到session
Header("Content-type: image/PNG");
//图片的长和高
$image_x=100;
$image_y=50;
$im = imagecreate($image_x,$image_y);
//这里取图片底色为白色
$bkg = ImageColorAllocate($im,255,255,255);
//显示的字体样式,这个要把文件放到对应的目录中,如果你没有文件就去window的字体文件中找一个吧。
$fnt = "simhei.ttf";
//为图像分配一些颜色
$white=ImageColorAllocate($im,234,185,95);
//在图片上画椭圆弧,指定下坐标点
imagearc($im, 150, 8, 20, 20, 75, 170, $white);
imagearc($im, 180, 7,50, 30, 75, 175, $white);
//在图片上画一条线段,指定下坐标点
imageline($im,20,20,180,30,$white);
imageline($im,20,18,170,50,$white);
imageline($im,25,50,80,50,$white);
//乱点的数量
$noise_num=3000;
$line_num=50;
//各种混乱字符的颜色
$rectangle_color=imagecolorallocate($im,0xAA,0xAA,0xAA);
$noise_color=imagecolorallocate($im,0x00,0x00,0x00);
$font_color=imagecolorallocate($im,0x00,0x00,0x00);
for($i=0;$i<$noise_num;$i++)
{
    //在一个坐标点上画一个单一像素,这个点上面定义了,是黑色的。
    //imagesetpixel($im,mt_rand(0,$image_x),mt_rand(0,$image_y),$noise_color);
}
for($i=0;$i<$line_num;$i++)
{
    $line_color=imagecolorallocate($im,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255));
    //在两个坐标点间画一条线,颜色在上面定义
    imageline($im,mt_rand(0,$image_x),mt_rand(0,$image_y),mt_rand(0,$image_x),mt_rand(0,$image_y),$line_color);    
}
for ($i=0;$i<4;$i++)
{
    ImageTTFText($im, rand(18,20), rand(0,20), rand(($image_x/4)*$i+$image_x/100,($image_x/4)*$i+$image_x/8), rand($image_y/2+$image_y/10,$image_y/2+$image_y/5), $font_color, $fnt, $str[$i]); 

}
ImagePNG($im);
ImageDestroy($im);
?>

  那根据第一点,大家首先应该会想到数字的验证码,因为这容易,随机生成个几个数字,然后拼起来也就行了,像酱紫!

后来有了纯汉字验证码,我记得最早是QQ首创的吧?(忽略上面的文字吧~~)

字体文件:simhei.rar点击此处本站下载。

图片 1图片 2

QQ验证

注意:

1 $validateCode = '';
2 for ($i = 0; $i < 4; $i ++) {
3     $validateCode .= rand(0, 9);
4 }
5 echo $validateCode;

百度贴吧验证码

中文汉字验证码单独执行,然后获取session会发现验证码和session内容不一致。但是在img
标签中src属性中引用这个中文汉字验证码文件时,然后获取session,这时两者内容时一致的。

View Code

不记得是哪里的gif动画型的了,现在也有挺多引用的

感兴趣的朋友可以对此进一步加以完善。

  然后仔细想想,现在的网站验证码都有字母,可这玩意儿都没字母,怎么呢?然后又想到,直接把上面那玩意儿搞成十六进制就好了。

第三阶段:算式型

图片 3图片 4

首次见到这个,是在dz论坛上,现在很多类似的论坛上都采用了。也有一些演变,如下图

1 $validateCode = '';
2 for ($i = 0; $i < 4; $i ++) {
3     $validateCode .= dechex(rand(0, 16));
4 }  
5 echo $validateCode;

最常见的加减乘除数学算式型的验证码

View Code

类似这种知识问答也有,但不多

  好像有点自作聪明的赶脚呀,不过想想,也算是有几个字母了,可却只有a,b,c,d,e,f,那要是需要所有字母咋办呢?哈哈,在想想也就想到把所有的字母和数字等在一个字符串中列出来,然后通过随机下标的形式去
随机获取对应的值,也就成了这样:

这个呢….呃….忽略吧!

图片 5图片 6

第四阶段:创新型

1 $validateCode = '';
2 $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
3 for ($i = 0; $i < 4; $i ++) {
4     $validateCode .= $str[rand(0, strlen($str))];
5 }  
6 echo $validateCode;

V1、广告型,把验证码和商业结合起来。其实这个只是汉字或数字型验证码的一个微创新

View Code

不再是枯燥的数字或算式

  哈哈,终于像验证码里的随机数了,不过看到下面的方法,有总瞬间被秒的赶脚呀:

V2、视频型,把验证码和广告结合起来,以视频的形式展现出来。国外已经有成功的案例,在国内深圳曾有一家,风光了一下就消失了…….国外的有DoubleRecall、SolveMedia和NuCaptcha三家验证码广告公司

echo substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'), 0, 4);

V3、游戏型,这个也是我最近才看到的这种广告形式,比较好玩,类似拼图一样。

  str_shuffle方法将字符串内容打乱,substr($str, 0,
4)取到了前四个数。这样是完全没有问题的!不过细心的看的出来,这样的验证码里的内容是不会重复的。

示案例示意图请点这里,无法上传。

 

总结来说,无论验证码如何演变,都不能抛弃一个基本原则:尽可能不要困扰用户的使用体验。

  以上验证码也就产生了,接下来也就要将验证码用PHP画出来了。

上面的这些验证码,可以发现技术一直发展,花样一直翻新,虽然可能对于机器人的破解带来了很大的障碍,但同时也增加了用户的使用难度。尤其是早期的验证码时代,字形越来越扭曲,颜色越来越花,字母之间靠的越来越近,输入的时候痛苦万分。

图片 7图片 8

就没有一个相对双赢的局面吗?未来验证码要怎么发展?

 1 $validateCode = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'), 0, 4);
 2 
 3 // 创建一张宽为110px,高为25px的图片
 4 $img = imagecreatetruecolor(110, 25);
 5 // 将图片的背景颜色设置成黑色,颜色值分别对应RGB
 6 $bgcolor = imagecolorallocate($img, 0, 0, 0);
 7 
 8 // 创建白色
 9 $white = imagecolorallocate($img, 255, 255, 255);
10 
11 // 添加文字在图片中,第二个参数为文字的大小,只能在1~5,第三个参数为x坐标,第4个参数为y坐标,第5个参数为文字的内容,第6个参数为文字的颜色
12 imagestring($img, rand(3, 5), rand(0, 80), rand(2, 10), $validateCode, $white);
13 
14 // 添加文字在图片中,第二个参数为文字的大小,只能在1~5,第三个参数为x坐标,第4个参数为y坐标,第5个参数为文字的内容,第6个参数为文字的颜色
15 imagestring($img, rand(3, 5), rand(0, 80), rand(2, 10), $validateCode, $white);

小小的YY一下:

View Code

1、和电商结合,比如输完这个验证码(复杂点也能接受),可以得到一定的优惠折扣(一淘在上次大改版后,有一阶段是这样做的)。

图片 9  

2、和游戏结合,输验证码的同时,可以得到一个游戏大礼包什么的。

  当然,这样的话验证码就太好识别了,就只是单纯的黑底白字,为了增加点难度,我们就多加几条线叠加在验证码的上面。

3、有个专属的验证码管理中心,像域名一样,申请后就永远属于你,真正的通用码(类似gravatar)。

图片 10图片 11

4、轻量SNS,让网站已注册网友出验证码,类似于题库里挑选题目一样…

 1 $validateCode = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'), 0, 4);
 2 
 3 // 创建一张宽为110px,高为25px的图片
 4 $img = imagecreatetruecolor(110, 25);
 5 // 将图片的背景颜色设置成黑色,颜色值分别对应RGB
 6 $bgcolor = imagecolorallocate($img, 0, 0, 0);
 7 // imagefill($img, 10, 10, $bgcolor);
 8 
 9 // 创建白色
10 $white = imagecolorallocate($img, 255, 255, 255);
11 
12 for ($i = 0; $i < 30; $i ++) {
13     // 在图片上画线,其中第2个参数表示线的x起始坐标,第3个参数表示线的y起始坐标,第4个参数表示x的终止坐标,第5个参数表示y的终止坐标,第6个参数表示颜色,此处生成一个随机颜色
14     imageline($img, rand(0, 110), rand(0, 50), rand(0, 110), rand(0, 50), imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255)));
15 }
16 
17 // 添加文字在图片中,第二个参数为文字的大小,只能在1~5,第三个参数为x坐标,第4个参数为y坐标,第5个参数为文字的内容,第6个参数为文字的颜色
18 imagestring($img, rand(3, 5), rand(0, 80), rand(2, 10), $validateCode, $white);
19 
20 // 返回成图片
21 header('Content-type: image/png');
22 imagepng($img);

5、其它。。。

View Code

图片 12

  结果也就成了这样,当然,要想实现验证码,这样还是不够滴,需要通过将验证码生成的随机数存到服务器的session中,$_SESSION[‘validate’]

$validateCode;然后在通过客户端输入的验证码与之对比即可。PHP中屌屌的验证码也就这样实现了,当然,前面也说过了,这是最基础的代码,可以通过你的想法将其改变为实现算术的验证码,中文的验证码,或其它一些有趣的验证码,以减少其枯燥性又实现安全性。

 

  大家有没有什么其它屌屌的验证码分享与我呢?

 


发表评论

电子邮件地址不会被公开。 必填项已用*标注