博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP 实现“贴吧神兽”验证码
阅读量:7017 次
发布时间:2019-06-28

本文共 11529 字,大约阅读时间需要 38 分钟。

最早看到 “贴吧神兽” 验证码是在百度贴吧,吧主防止挖坟贴,放出了究极神兽验证码

例如:

地址:

 

可以用 PHP + JavaScript 实现该种类型的验证码。

使用 jQuery 版本:jQuery 1.9.1

框架使用 ThinkPHP 3.2.3,自定义的验证码类基于 TP 的验证码类

 

最终效果图:

 

自定义验证码类路径:/Application/Home/Common/VerivyPostBar.class.php

控制器:/Application/Home/Controller/PostBarController.class.php

视图:/Applicable/Home/View/PostBarVerify/index.html

 

自定义验证码类 /Application/Home/Common/VerivyPostBar.class.php

imageW || $this->imageW = $this->length*$this->fontSize*1.5 + $this->length*$this->fontSize/2; // 图片高(px) $this->imageH || $this->imageH = $this->fontSize * 2.5; // 建立一幅 $this->imageW x $this->imageH 的透明图像 $this->_image = imagecreatetruecolor($this->imageW, $this->imageH); imagesavealpha($this->_image, true); $trans_colour = imagecolorallocatealpha($this->_image, 0, 0, 0, 127); imagefill($this->_image, 0, 0, $trans_colour); // 验证码字体随机颜色 $this->_color = imagecolorallocate($this->_image, mt_rand(1,150), mt_rand(1,150), mt_rand(1,150)); // 验证码使用随机字体 $ttfPath = $_SERVER['DOCUMENT_ROOT'].'/ThinkPHP/Library/Think/Verify/' . ($this->useZh ? 'zhttfs' : 'ttfs') . '/'; if(empty($this->fontttf)){ $dir = dir($ttfPath); $ttfs = array(); while (false !== ($file = $dir->read())) { if($file[0] != '.' && substr($file, -4) == '.ttf') { $ttfs[] = $file; } } $dir->close(); $this->fontttf = $ttfs[array_rand($ttfs)]; } $this->fontttf = $ttfPath . $this->fontttf; if($this->useImgBg) { $this->_background(); } if ($this->useNoise) { // 绘杂点 // $this->_writeNoise(); } if ($this->useCurve) { // 绘干扰线 $this->_writeCurve(); } // 绘验证码 $code = array(); // 验证码 $codeNX = 0; // 验证码第N个字符的左边距 if($this->useZh){ // 中文验证码 for ($i = 0; $i<$this->length; $i++) { $code[$i] = iconv_substr($this->zhSet, $i, 1, 'utf-8'); imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $this->fontSize*($i+1)*1.5, $this->fontSize + mt_rand(10, 20), $this->_color, $this->fontttf, $code[$i]); } // 备选验证码区域(9个汉字) $len_pre_row = $this->area_length / $this->rows; // 每行的字数 for($r = 0; $r < $this->rows; $r++) { $flag = 1; $start = $r * $len_pre_row; $end = $r * $len_pre_row + $len_pre_row - 1; $code_ = array(); for ($i = $start; $i<$end + 1; $i++) { $code_[$i] = iconv_substr($this->code_area, $i, 1, 'utf-8'); // @param image // @param size // @param angle // @param x // @param y // @param color // @param fontfile imagettftext($this->_image, $this->fontSize, mt_rand(-20, 20), $this->fontSize*2 * $flag, $this->fontSize + 50 * $r + 120, $this->_color, $this->fontttf, $code_[$i]); $flag += 2; // 控制验证码备选字符的x坐标 } } } // 保存验证码 $key = $this->authcode($this->seKey); $code = $this->authcode(strtoupper(implode('', $code))); $secode = array(); $secode['verify_code'] = $code; // 把校验码保存到session $secode['verify_time'] = NOW_TIME; // 验证码创建时间 session($key.$id, $secode); header('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate'); header('Cache-Control: post-check=0, pre-check=0', false); header('Pragma: no-cache'); header("content-type: image/png"); // 保存图像至硬盘 imagepng($this->_image, 'Public/Home/Images/verifyimage.png'); // 输出图像 // imagepng($this->_image); readfile('Public/Home/Images/verifyimage.png'); imagedestroy($this->_image); } /** * 画杂点 * 往图片上写不同颜色的字母或数字 */ private function _writeNoise() { $codeSet = '2345678abcdefhijkmnpqrstuvwxyz'; for($i = 0; $i < 10; $i++){ //杂点颜色 $noiseColor = imagecolorallocate($this->_image, mt_rand(150,225), mt_rand(150,225), mt_rand(150,225)); for($j = 0; $j < 5; $j++) { // 绘杂点 imagestring($this->_image, 5, mt_rand(-10, $this->imageW), mt_rand(-10, $this->imageH), $codeSet[mt_rand(0, 29)], $noiseColor); } } } /** * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数) * * 高中的数学公式咋都忘了涅,写出来 * 正弦型函数解析式:y=Asin(ωx+φ)+b * 各常数值对函数图像的影响: * A:决定峰值(即纵向拉伸压缩的倍数) * b:表示波形在Y轴的位置关系或纵向移动距离(上加下减) * φ:决定波形与X轴位置关系或横向移动距离(左加右减) * ω:决定周期(最小正周期T=2π/∣ω∣) * */ private function _writeCurve() { $px = $py = 0; // 曲线前部分 $A = mt_rand(1, $this->imageVerifyH/2); // 振幅 $b = mt_rand(-$this->imageVerifyH/4, $this->imageVerifyH/4); // Y轴方向偏移量 $f = mt_rand(-$this->imagimageVerifyHeH/4, $this->imageVerifyH/4); // X轴方向偏移量 $T = mt_rand($this->imageVerifyH, $this->imageW*2); // 周期 $w = (2* M_PI)/$T; $px1 = 0; // 曲线横坐标起始位置 $px2 = mt_rand($this->imageW/2, $this->imageW * 0.8); // 曲线横坐标结束位置 for ($px=$px1; $px<=$px2; $px = $px + 1) { if ($w!=0) { $py = $A * sin($w*$px + $f)+ $b + $this->imageVerifyH/2; // y = Asin(ωx+φ) + b $i = (int) ($this->fontSize/5); while ($i > 0) { imagesetpixel($this->_image, $px + $i , $py + $i, $this->_color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多 $i--; } } } } /* 加密验证码 */ private function authcode($str){ $key = substr(md5($this->seKey), 5, 8); $str = substr(md5($str), 8, 10); return md5($key . $str); } /** * 绘制背景图片 * 注:如果验证码输出图片比较大,将占用比较多的系统资源 */ private function _background() { $path = dirname(__FILE__).'/Verify/bgs/'; $dir = dir($path); $bgs = array(); while (false !== ($file = $dir->read())) { if($file[0] != '.' && substr($file, -4) == '.jpg') { $bgs[] = $path . $file; } } $dir->close(); $gb = $bgs[array_rand($bgs)]; list($width, $height) = @getimagesize($gb); // Resample $bgImage = @imagecreatefromjpeg($gb); @imagecopyresampled($this->_image, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height); @imagedestroy($bgImage); } }

  

控制器 /Application/Home/Controller/PostBarController.class.php

display(); } // 验证 public function check_verify($code) { $verify = new VerifyPostBar(); if(!$verify->check($code)) { return 400; } else { return 200; } } // 准备验证码字符 public function prepare_code() { // 验证码的长度 $length = 4; // 验证码选区长度 $selects = 12; // 相近的汉字为一组,从6组36个汉字中抽出4组12个汉字组成验证码图片组 $zhSet = array( array( '已','己','乙','巳','九','走' ), array( '田','由','甲','申','白','日' ), array( '鱼','渔','俞','喻','瑜','愈' ), array( '请','清','情','青','晴','蜻' ), array( '宝','玉','穴','必','空','控' ), array( '子','仔','籽','孜','吱','资' ) ); $tmp = array(); $count = count($zhSet); $tmp = $this->rand(0, $count - 1, 4); // 随机生成4个不重复的数(0-5组里面选出4组)作为下标 $chars = array(); foreach($tmp as $key => $val) { $chars[] = $this->choose($zhSet, $val, 3);// 每组3个数 } // 从每组一维数组中选出一个组成长度为4的验证码 foreach($chars as $key => $val) { $k = mt_rand(0, count($val) - 1); $code[] = $val[$k]; // 验证码 unset($chars[$key][$k]); } // dump($code); // dump($chars);die; // 把数组合并成一维数组 $characters = array(); foreach($chars as $key => $val) { foreach($val as $k => $v) { $characters[] = $v; } } // 备选验证码区数组 $code_area_array = array_merge($code, $characters); shuffle($code_area_array); // 备选验证码区字符串 $code_area = implode('', $code_area_array); $code = implode('', $code); $codes['code_area'] = $code_area; $codes['code_area_array'] = $code_area_array; $codes['code'] = $code; $codes['characters'] = $characters; $codes['length'] = $length; $_SESSION['code_area_array'] = $code_area_array; return $codes; } // 显示验证码 public function verify() { $codes = $this->prepare_code(); $conf = array( 'useZh' => true, 'zhSet' => $codes['code'], 'code_area' => $codes['code_area'], 'length' => $codes['length'], // 验证码长度(汉字个数) 'rows' => 3, //备选区域3行 'area_length'=> mb_strlen($codes['code_area'], 'utf-8'), // 备选区域汉字个数 'fontSize' => 20, 'imageW' => 320, 'imageH' => 600, 'imageVerifyH' => 45, // 4字验证码区域高度 ); $verify = new VerifyPostBar($conf); $verify->entryProcess(); } // 从一组连续的数字中选出不重复的个数 // @param $start 数字的开始值 // @param $end 数字的结束值 // @param $count 选出的个数 public function rand($start, $end, $count) { $tmp = range($start, $end); $tmp = array_rand($tmp, $count); return $tmp; } // 从每组汉字(一组6个)中选出n(4)个 // @param $array 二维数组 // @param $key 数组 $array 的下标 // @param $n 选出几个 public function choose($array, $key, $n) { $arr = $array[$key]; $count = count($arr); $tmp_key = $this->rand(0, $count - 1, $n); $chars = array(); foreach($tmp_key as $val) { $chars[] = $arr[$val]; } return $chars; } // 记录点击次数,如果次数达到4次就做出判断,验证码输入是否正确 public function count_ckick() { session_start(); // 坐标数组 $codes = $_SESSION['code_area_array']; $xy = array( 'line1_y'=>array( 'x1'=>0, 'x2'=>1, 'x3'=>2, 'x4'=>3, ), 'line2_y'=>array( 'x1'=>4, 'x2'=>5, 'x3'=>6, 'x4'=>7, ), 'line3_y'=>array( 'x1'=>8, 'x2'=>9, 'x3'=>10, 'x4'=>11, ) ); if(! isset($_POST['clear']) || $_POST['clear'] != 1) { $_SESSION['count'] = $count = $_POST['count']; if($count > 4) { $_SESSION['count'] = 4; } else { // 记录选择的验证码文字 $x = $_POST['x']; $y = $_POST['y']; foreach($xy as $key => $val) { foreach($val as $k => $v) { if($y == $key) { if($x == $k) { $code_key = $codes[$v]; } } } } } if(! isset($_SESSION['input_code'])) { $_SESSION['input_code'] = $code_key; } else { $_SESSION['input_code'] .= $code_key; } $return = '点击了 '.$_SESSION['count'].' 次, 选中的汉字是: '.$code_key.' 输入的验证码是: '.$_SESSION['input_code']; if($count == 4) { $code = $this->check_verify($_SESSION['input_code']); if($code == 200) { $return .= ' 输入正确'; } else { $return .= ' 输入错误'; } } echo $return; } else { // 清除点击次数 $_SESSION['count'] = 0; unset($_SESSION['input_code']); echo '成功清除了点击次数,点击次数为',$_SESSION['count'],'次'; } } // 获取session中记录的点击次数 public function record_click() { session_start(); if(! isset($_SESSION['count'])) { $_SESSION['count'] = 0; } echo $_SESSION['count']; } // 修改点击记录数 public function update_click() { session_start(); if(! isset($_SESSION['count'])) { $_SESSION['count'] = 0; } else { $newcount = $_SESSION['count'] + $_POST['times']; if($newcount < 0) { $_SESSION['count'] = 0; unset($_SEIION['input_code']); } else { $_SESSION['count'] = $newcount; $_SESSION['input_code'] = mb_substr($_SESSION['input_code'], 0, -1, 'utf-8'); } } echo '点击数是:'.$_SESSION['count'].' 验证码是:'.$_SESSION['input_code']; } }

  

视图 /Applicable/Home/View/PostBarVerify/index.html

	
Document

点击验证码图片换一张

验证码

点击框内文字输入上图中汉字

{:U('Home/PostBarVerify/verify','','')}

  

演示

初始状态:

 

输入验证码:

 

输入完成,返回结果,错误时:

 

输入完成,返回结果,正确时:

 

删除验证码:

 

刷新验证码:

 

参考:

转载地址:http://rhwxl.baihongyu.com/

你可能感兴趣的文章
网络基础CCNP|SDN与日志
查看>>
Python3.X Socket 一个编码与解码的坑
查看>>
vs2015未能正确加载“ProviderPackage”包。
查看>>
PHP带头大哥讲解几种综合PHP网络服务器系统的选择!
查看>>
MySQL数据表所有操作命令
查看>>
使用SQLRootKit网页数据库后门控制案例
查看>>
Jmeter性能测试-----参数化方法CSVRead函数
查看>>
iptables的备份及脚本构成
查看>>
二级缓存相关属性
查看>>
Python内置容器(1)——列表,元组,集合
查看>>
ASP.NET中实现回调
查看>>
OC学习笔记[注意事项]
查看>>
使用Spinner和setDropDownViewResource
查看>>
机房日常技术总结——Linux篇
查看>>
如何从计算机中删除 Exchange Server 2003
查看>>
邮件服务器的基础知识概述
查看>>
C# 视频监控系列(1):准备
查看>>
Lync2013 升级错误总结7 Lync2013 外部共享PPT提示:网络连接已丢失或服务器正忙,...
查看>>
JSSE编程基本代码
查看>>
webcdn故障处理一例
查看>>