php 验证码(倾斜,正弦干扰线,黏贴,旋转)


Posted in PHP onJune 29, 2013

好久没有写帖子了。一直忙着新的项目。 最近,做验证码程序,一直想做一个简洁大方,自动识别比较困难的。 通过这些时候整理搜集,发现一般做法有以下几种方案:
1、字体变型 (一般通过算法,进行扭曲,比较有代表性就是:http://code.google.com/p/cool-php-captcha/

php 验证码(倾斜,正弦干扰线,黏贴,旋转)

2、字体黏贴 (这里面以qq验证码为代表了,目前网上还是很难找到,破解qq验证码的)

php 验证码(倾斜,正弦干扰线,黏贴,旋转)

3、干扰线,噪点 (这种识别起来相当容易,很容易被程序自动化识别)
对于上面提到,第1,2 二种方法,在识别时候,是比较困难的。个人比较喜欢第二种方法,感觉看起来不是很费力。而扭曲的文字,总觉得怪怪的。 哈哈,纯粹个人喜好了。
实现代码:

<?php
/**
 *带文字旋转,倾斜,黏贴,加正弦干扰线验证码*
 *@version  0.1
 *@author http://www.cnblogs.com/chengmo
 *@copyright 程默 QQ:8292669
 */
class Utils_Caption
{
 var $Width      = 60;           //图片宽
 var $Height     = 30;           //图片高
 var $Length     = 4;            //验证码位数
 var $BgColor    = "#FFFFFF";    //背景色
 var $TFonts = array("font.ttf");
 var $TFontSize=array(17,20); //字体大小范围
 var $TFontAngle=array(-20,20); //旋转角度
 var $Chars   = "0123456789";         //验证码范围(字母数字)
 var $Code    = array();              //验证码
 var $Image   = "";              //图形对象
 var $FontColors=array('#f36161','#6bc146','#5368bd');  //字体颜色,红绿蓝
 var $TPadden = 0.75;///字符间距,多少个字符
 var $Txbase = 5;///x轴两边距离
 var $Tybase =5 ;///y轴两边距离
 var $TLine =true; ///画干扰线
 public  function RandRSI() ///生成验证码
 {
  $this->TFontAngle=range($this->TFontAngle[0],$this->TFontAngle[1]);
  $this->TFontSize=range($this->TFontSize[0],$this->TFontSize[1]);
  $arr=array();
  $Chars=$this->Chars;
  $TFontAngle=$this->TFontAngle;
  $TFontSize=$this->TFontSize;
  $FontColors=$this->FontColors;
  $code="";
  $font=dirname(__FILE__)."/font/".$this->TFonts[0];
  $charlen=strlen($Chars)-1;
  $anglelen=count($TFontAngle)-1; // 角度范围
  $fontsizelen=count($TFontSize)-1; // 角度范围
  $fontcolorlen=count($FontColors)-1; // 角度范围
  for($i=0;$i<$this->Length;$i++) ///得到字符与颜色
  {
   $char=$Chars[rand(0,$charlen)]; ///得到字符
   $angle=$TFontAngle[rand(0,$anglelen)]; ///旋转角度
   $fontsize=$TFontSize[rand(0,$fontsizelen)]; ///字体大小
   $fontcolor=$FontColors[rand(0,$fontcolorlen)]; ///字体大小
   $bound=$this->_calculateTextBox($fontsize,$angle,$font,$char); ///得到范围
   $arr[]=array($fontsize,$angle,$fontcolor,$char,$font,$bound);  ///得到矩形框
   $code.=$char;
  }
  $this->Code=$arr; //验证码
  return $code;
 }
 public function Draw() ///画图
 {
  if(empty($this->Code)) $this->RandRSI();
  $codes=$this->Code; ///用户验证码
  $wh=$this->_getImageWH($codes);
  $width=$wh[0];
  $height=$wh[1]; ///高度
  $this->Width=$width;
  $this->Height=$height;
  $this->Image = imageCreate( $width, $height );
  $image=$this->Image;
  $back = $this->_getColor2($this->_getColor( $this->BgColor)); ///背景颜色
  imageFilledRectangle($image, 0, 0, $width, $height, $back); ///填充背景
  $TPadden=$this->TPadden;
  $basex=$this->Txbase;
  $color=null;
  foreach ($codes as $v) ///逐个画字符
  {
   $bound=$v[5];
   $color=$this->_getColor2($this->_getColor($v[2]));
   imagettftext($image, $v[0], $v[1], $basex, $bound['height'],$color , $v[4], $v[3]);
   $basex=$basex+$bound['width']*$TPadden-$bound['left'];///计算下一个左边距
  }
  $this->TLine?$this->_wirteSinLine($color,$basex):null; ///画干扰线
  header("Content-type: image/png");
  imagepng( $image);
  imagedestroy($image);
 }
 /**
  *通过字体角度得到字体矩形宽度*
  *
  * @param int $font_size 字体尺寸
  * @param float $font_angle 旋转角度
  * @param string $font_file 字体文件路径
  * @param string $text 写入字符
  * @return array 返回长宽高
  */
 private function _calculateTextBox($font_size, $font_angle, $font_file, $text) {
  $box = imagettfbbox($font_size, $font_angle, $font_file, $text);
  $min_x = min(array($box[0], $box[2], $box[4], $box[6]));
  $max_x = max(array($box[0], $box[2], $box[4], $box[6]));
  $min_y = min(array($box[1], $box[3], $box[5], $box[7]));
  $max_y = max(array($box[1], $box[3], $box[5], $box[7]));
  return array(
  'left' => ($min_x >= -1) ? -abs($min_x + 1) : abs($min_x + 2),
  'top' => abs($min_y),
  'width' => $max_x - $min_x,
  'height' => $max_y - $min_y,
  'box' => $box
  );
 }
 private function  _getColor( $color ) //#ffffff
 {
  return array(hexdec($color[1].$color[2]),hexdec($color[3].$color[4]),hexdec($color[5].$color[6]));
 }
 private function  _getColor2( $color ) //#ffffff
 {
  return imagecolorallocate ($this->Image, $color[0], $color[1], $color[2]);
 }
 private function _getImageWH($data)
 {
  $TPadden=$this->TPadden;
  $w=$this->Txbase;
  $h=0;
  foreach ($data as $v)
  {
   $w=$w+$v[5]['width']*$TPadden-$v[5]['left'];
   $h=$h>$v[5]['height']?$h:$v[5]['height'];
  }
  return array(max($w,$this->Width),max($h,$this->Height));
 }
 //画正弦干扰线
 private function _wirteSinLine($color,$w)
 {
  $img=$this->Image;
  $h=$this->Height;
  $h1=rand(-5,5);
  $h2=rand(-1,1);
  $w2=rand(10,15);
  $h3=rand(4,6);
  for($i=-$w/2;$i<$w/2;$i=$i+0.1)
  {
   $y=$h/$h3*sin($i/$w2)+$h/2+$h1;
   imagesetpixel($img,$i+$w/2,$y,$color);
   $h2!=0?imagesetpixel($img,$i+$w/2,$y+$h2,$color):null;
  }
 }
}

外带字体:
font.ttf ,一个简单粗体文件。
php 验证码(倾斜,正弦干扰线,黏贴,旋转)

说明:先看下运行效果吧,大家也不要忙着复制运行了。

php 验证码(倾斜,正弦干扰线,黏贴,旋转)php 验证码(倾斜,正弦干扰线,黏贴,旋转)php 验证码(倾斜,正弦干扰线,黏贴,旋转)php 验证码(倾斜,正弦干扰线,黏贴,旋转)php 验证码(倾斜,正弦干扰线,黏贴,旋转)
主要特点是:旋转,然后黏贴,干扰线是线粗细可以变,然后正弦波形可以变化。
比较复杂是:calculateTextBox 这个函数,这个是得到字符旋转后的宽度高度。
demo:

$rsi = new Utils_Caption();
$rsi->TFontSize=array(15,17);
$rsi->Width=50;
$rsi->Height=25;
$code = $rsi->RandRSI();
session_start();
$_SESSION["CHECKCODE"] = $code;
$rsi->Draw();

好了,就写这么些了,代码还有很多不足之处。
点击下载代码
PHP 相关文章推荐
PHP脚本的10个技巧(1)
Oct 09 PHP
我的论坛源代码(五)
Oct 09 PHP
用PHP和ACCESS写聊天室(五)
Oct 09 PHP
基于PHP对XML的操作详解
Jun 07 PHP
CodeIgniter CLI模式简介
Jun 17 PHP
php中strtotime函数用法详解
Nov 15 PHP
PHP多态代码实例
Jun 26 PHP
php实现的Curl封装类Curl.class.php用法实例分析
Sep 25 PHP
PHP获取二维数组中某一列的值集合
Dec 25 PHP
实现PHP框架系列文章(6)mysql数据库方法
Mar 04 PHP
thinkPHP框架实现多表查询的方法
Jun 14 PHP
php数值计算num类简单操作示例
May 15 PHP
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
Jun 29 #PHP
探讨:web上存漏洞及原理分析、防范方法
Jun 29 #PHP
浅谈web上存漏洞及原理分析、防范方法(安全文件上存方法)
Jun 29 #PHP
解析web文件操作常见安全漏洞(目录、文件名检测漏洞)
Jun 29 #PHP
解析PHP中empty is_null和isset的测试
Jun 29 #PHP
浅析Dos下运行php.exe,出现没有找到php_mbstring.dll 错误的解决方法
Jun 29 #PHP
浅析PHP中的UNICODE 编码与解码
Jun 29 #PHP
You might like
PHP字符编码问题之GB2312 VS UTF-8解决方法
2011/06/23 PHP
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
php5.4以下版本json不支持不转义内容中文的解决方法
2015/01/13 PHP
简单介绍PHP非阻塞模式
2016/03/03 PHP
laravel配置Redis多个库的实现方法
2019/04/10 PHP
自动生成文章摘要的代码[JavaScript 版本]
2007/03/20 Javascript
ExtJS 2.0实用简明教程 之Border区域布局
2009/04/29 Javascript
JavaScript高级程序设计阅读笔记(六) ECMAScript中的运算符(二)
2012/02/27 Javascript
from表单多个按钮提交用onclick跳转不同action
2014/04/24 Javascript
JavaScript动态加载样式表的方法
2015/03/21 Javascript
jQuery树形插件jquery.simpleTree.js用法分析
2016/09/05 Javascript
js中scrollTop()方法和scroll()方法用法示例
2016/10/03 Javascript
jQuery弹出窗口打开链接的实现代码
2016/12/24 Javascript
微信小程序 五星评价功能的实现
2017/03/09 Javascript
jQuery获取复选框选中的当前行的某个字段的值
2017/09/15 jQuery
webpack构建换肤功能的思路详解
2017/11/27 Javascript
JavaScript日期工具类DateUtils定义与用法示例
2018/09/03 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
[01:08:17]2018DOTA2亚洲邀请赛3月29日 小组赛B组 EG VS VGJ.T
2018/03/30 DOTA
Python re模块介绍
2014/11/30 Python
快速查询Python文档方法分享
2017/12/27 Python
Python 查看list中是否含有某元素的方法
2018/06/27 Python
python 处理telnet返回的More,以及get想要的那个参数方法
2019/02/14 Python
Django框架验证码用法实例分析
2019/05/10 Python
快速解决Django关闭Debug模式无法加载media图片与static静态文件
2020/04/07 Python
python3定位并识别图片验证码实现自动登录功能
2021/01/29 Python
美国隐形眼镜网上商店:Lens.com
2019/09/03 全球购物
经典c++面试题二
2015/08/14 面试题
Net Remoting把服务器端激活两种模式
2014/01/22 面试题
分公司总经理岗位职责
2014/07/30 职场文书
停车位租赁协议书
2014/09/24 职场文书
学习群众路线的心得体会
2014/11/05 职场文书
2015年商场工作总结
2015/04/27 职场文书
教你用python实现一个无界面的小型图书管理系统
2021/05/21 Python
PostgreSQL13基于流复制搭建后备服务器的方法
2022/01/18 PostgreSQL