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生成便于打印的网页
Oct 09 PHP
php的日期处理函数及uchome的function_coomon中日期处理函数的研究
Jan 12 PHP
PHP安全配置详细说明
Sep 26 PHP
分享一个超好用的php header下载函数
Jan 31 PHP
ThinkPHP3.1.3版本新特性概述
Jun 19 PHP
php创建、获取cookie及基础要点分析
Jan 26 PHP
php开发中的页面跳转方法总结
Apr 26 PHP
浅析iis7.5安装配置php环境
May 10 PHP
php resizeimage 部分jpg文件 生成缩略图失败的原因分析及解决办法
Mar 23 PHP
php封装json通信接口详解及实例
Mar 07 PHP
PHP实践教程之过滤、验证、转义与密码详解
Jul 24 PHP
PHP空值检测函数与方法汇总
Nov 19 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
不用iconv库的gb2312与utf-8的互换函数
2006/10/09 PHP
PHP邮件专题
2006/10/09 PHP
php 8小时时间差的解决方法小结
2009/12/22 PHP
php IP转换整形(ip2long)的详解
2013/06/06 PHP
PHP Opcache安装和配置方法介绍
2015/05/28 PHP
PHP中如何使用session实现保存用户登录信息
2015/10/20 PHP
一个简单安全的PHP验证码类、PHP验证码
2016/09/24 PHP
静态页面下用javascript操作ACCESS数据库(读增改删)的代码
2007/05/14 Javascript
jQuery中的常用事件总结
2009/12/27 Javascript
jquery实现marquee效果(文字或者图片的水平垂直滚动)
2013/01/07 Javascript
深入剖析JavaScript编程中的对象概念
2015/10/21 Javascript
JavaScript模块规范之AMD规范和CMD规范
2015/10/27 Javascript
使用jQuery mobile库检测url绝对地址和相对地址的方法
2015/12/04 Javascript
js表单处理中单选、多选、选择框值的获取及表单的序列化
2016/03/08 Javascript
JS实现“隐藏与显示”功能(多种方法)
2016/11/24 Javascript
浅谈angular2子组件的事件传递(任意组件事件传递)
2018/09/30 Javascript
bootstrap tooltips在 angularJS中的使用方法
2019/04/10 Javascript
深入解析vue 源码目录及构建过程分析
2019/04/24 Javascript
小程序实现上下移动切换位置
2019/09/23 Javascript
layui实现二维码弹窗、并下载到本地的方法
2019/09/25 Javascript
vue仿ios列表左划删除
2019/09/26 Javascript
使用Python的Scrapy框架编写web爬虫的简单示例
2015/04/17 Python
Python中利用sqrt()方法进行平方根计算的教程
2015/05/15 Python
详解Python实现按任意键继续/退出的功能
2016/08/19 Python
python 捕获 shell/bash 脚本的输出结果实例
2017/01/04 Python
一文带你了解Python中的字符串是什么
2018/11/20 Python
CSS3点击按钮实现背景渐变动画效果
2016/10/19 HTML / CSS
财务管理专业应届毕业生求职信
2013/09/22 职场文书
即将毕业大学生自荐信
2014/01/24 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
2015年民兵整组工作总结
2015/07/24 职场文书
办公用品管理制度
2015/08/04 职场文书
2016年寒假社会实践活动总结
2015/10/10 职场文书
PostgreSQL存储过程实用脚本(二):创建函数入门
2021/04/05 PostgreSQL
JavaScript小技巧带你提升你的代码技能
2021/09/15 Javascript
javascript遍历对象的五种方式实例代码
2021/10/24 Javascript