原生态字模生成变形错位的图片验证码

hudie631489527 2012-01-19 09:05:30
一年又过去了,在这最后回家之前留下最后的手印
原本是为了破解12306.cn的验证码,经过一翻奋斗,还是只处于研究状态,一直没有下手,时间不多,烦心的事多,所以静不下来弄.(来年了,就着手这个了,为了来年能够用自己的程序买到火车票)
机原巧合,在破解图片的时候,想到自己之前写的图片验证码真是弱爆了,所以现在从不容易被人破解的角度重新写了此程序:
主要功能
1.生成字模(在生成字符串字模后,就不需要字体文件)
2.图片中字符旋转和交错
代码在此:(欢迎大家一起来讨论研究更好的实现方法)
原文地址: http://www.onlypo.com/archives/139

<?php
/****
* @auth: Buty
* @data: 2012-1-12
* @Func: 生成随机变形的验证码
* 准备工作:
1.创建字模数组 $captcha = new Captcha;
$captcha->createZiMo();
生成验证码:
$captcha->displayCaptcha();
*/
class Captcha {
private $words = '123456789ABCDEFGHIJKLNPQRSTUVXYZ';
private $width = 25; //字模宽度
private $height = 25; //字模高度
private $img;
private $text_color; //文字颜色
public $zimo_dir = 'zimopics/'; //字模生成文件目录
private $suffix = '.jpg'; //字模图片
public $zimo_file = 'zimo.php'; //字模数组文件
private $zimo = NULL;
private $font_file = 'arial.ttf';//ttf字体文件, 生成字模图片时必须的,在系统中随便找一个
//初始化画布
public function Captcha() {
$width = 120;
$height = 50;
if(!extension_loaded('gd')) { //需要gd扩展的支持
exit('GD extension is supported,please load GD extension and go on.');
}
$this->img = imagecreatetruecolor($width, $height);
$this->text_color = imagecolorallocate($this->img, 0, 0, 255);
$bg_color = imagecolorallocate($this->img, 255, 255, 255);
ImageFilledRectangle($this->img, 0, 0, $width, $height, $bg_color);
}
//保存验证码到session, 对于不同存储验证码的手段,此方法直接重写
function saveCode($code) {
session_start();
$_SESSION['code'] = implode('',$code);
setcookie('code', $_SESSION['code']);
}
//产生验证码
private function productNum($len) {
$num = array();
$total_len = strlen($this->words);
for($i = 0; $i < $len; $i++) {
$index = mt_rand(0, ($total_len - 1));
$num[]= $this->words[$index];
}
return $num;
}
//显示验证码
function displayCaptcha($len = 4) {
if(empty($len)) $len = 4;
$code = $this->productNum($len);
foreach($code as $k => $v) {
$this->addZiMo($v, $k * $this->width);
}
//保存验证码到session
$this->saveCode($code);
//输出图片
$this->showNewPic();
}
//添加新字模到图片
function addZiMo($str, $width=0) {
if(!$this->zimo) {
$this->loadZiMo();
}
$str = strtoupper($str);
if(isset($this->zimo[$str])) {
$this->rotateZiMo($this->zimo[$str],$width);
}
}
//加载字模数据
function loadZiMo() {
if(is_file($this->zimo_dir . $this->zimo_file)) {
$this->zimo = include $this->zimo_dir . $this->zimo_file;
//解析字模点阵
$this->zimo = $this->strToArray($this->zimo);
} else {
exit('Zimo file not exists, please use method `createZiMo` create Zimo file.');
}
}
//旋转字模打点
function rotateZiMo($data, $width=0) {
$angle = $this->randAngle(); //角度随机
$width = $this->randDistance($width);//距离随机

foreach($data as $i => $v) {
foreach($v as $j => $vs) {
if(!$vs) {
$jindex = $j+$width;
$res = $this->circleCoord($width,0,$jindex,-$i, $angle);
$new_i = floor(abs($res['y']));
$new_j = floor(abs($res['x']));
imagesetpixel($this->img, $new_j, $new_i, $this->text_color);
}
}
}
return $data;
}
//角度变换
function randAngle() {
return mt_rand(-15,15); //角度随机
}
//距离变换
function randDistance($width) {
return $width + mt_rand(15,20); //距离随机
}
//根据圆心坐标,圆上一点坐标,角度,计算另一坐标
function circleCoord($x0,$y0,$x1,$y1,$angle) {
$r = sqrt(($x1 - $x0)*($x1 - $x0) + ($y1 - $y0)*($y1 - $y0));
$arc = ($x1 - $x0) / $r;
$angle0_rad = acos($arc);
$angle0_rad = rad2deg($angle0_rad);
$angle_new = $angle0_rad + $angle;
$new_x = $x0 + $r * cos(deg2rad($angle_new));
$new_y = $y0 + $r * sin(deg2rad($angle_new));
return array('x' => $new_x, 'y' => $new_y);
}

/*****************************************自行创建字模图片与字模数组文件********************************/
//创建字模图片
function createZiMoPic($words = '') {
if(!file_exists($this->font_file)) { //字体需要存在
exit('Font file no exists.');
}
$this->checkDoc(); //如果目录不存在,自动生成
if(empty($words)) $words = $this->words;
for($i = 0; $i < strlen($words); $i++) {
$num = $words[$i];
$height = 25; //高度
$width = 25; //一个字符宽度
$font_size = 25; //字体大小
$font = $this->font_file; //ttf字体
$x = 0;
$y = 0;
$angle = 0;
$img = imagecreatetruecolor($width, $height);
$text_color = imagecolorallocate($img, 0, 0, 255);
$bg_color = imagecolorallocate($img, 255, 255, 255);
//其左上角坐标为 x,y
ImageFilledRectangle($img, $x, $y, $width, $height, $bg_color);
//由 x,y 所表示的坐标定义了第一个字符的基本点(大概是字符的左下角)
imagettftext($img, $font_size, $angle, $x, $height, $text_color, $font, $num);
ImageJPEG($img, $this->zimo_dir . strtoupper($num) . $this->suffix);
imagedestroy($img);
}
}
//检测目录是否存在,不存在创建
function checkDoc() {
if(!is_dir($this->zimo_dir)) {
mkdir($this->zimo_dir,0777,true);
}
}
//创建字模
function createZiMo($words = '') {
if(empty($words)) $words = $this->words;
$this->createZiMoPic($words);
$data = array();
if(is_dir($this->zimo_dir)) {
if($dp = opendir($this->zimo_dir)) {
while (($file = readdir($dp)) !== false) {
if($file != '.' && $file != '..' && $this->suffix == strrchr($file, '.')) {
$key = substr($file, 0, -strlen($this->suffix));
$value = $this->createZiMoDot($this->zimo_dir . $file);
$data[$key] = $value;
}
}
closedir($dp);
}
}
$data = $this->arrayToStr($data);
$this->writeZiMoFile($data);
}
//写入字模文件
function writeZiMoFile($data) {
$fp = fopen($this->zimo_dir . $this->zimo_file, 'w');
$data = $this->stripWhiteEnter(var_export($data, true));
fwrite($fp, "<?php\r\nreturn ".$data."\r\n?>");
fclose($fp);
}
//将三维数组改写成字符串
function arrayToStr($data) {
foreach($data as $k => $v) {
$str = '';
foreach($v as $sk => $sv) {
foreach($sv as $ssk => $ssv) {
$str .= $ssv;
}
}
unset($data[$k]);
$data[$k] = $str;
}
return $data;
}
//将一维数组按规律改写成三维数组
function strToArray($data) {
$cut_words = 25; //将字符串切成25个小数组
foreach($data as $k => $v) {
unset($data[$k]);
$strlens = strlen($v);
for($i = 0; $i < $strlens; $i++) {
$secindex = floor($i/$cut_words);
$data[$k][$secindex][] = $v[$i];
}
}

return $data;
}
// 去除代码中的空白和换行
function stripWhiteEnter($content) {
$stripword = array(' ','\t',"\r","\n","\r\n");
$content = str_replace($stripword,"",$content);
return $content;
}
//生成字模点阵
function createZiMoDot($picfile) {
$res = imagecreatefromjpeg($picfile);
$size = getimagesize($picfile);
$data = array();
for($i=0; $i < $size[1]; ++$i) {
for($j=0; $j < $size[0]; ++$j) {
$rgb = imagecolorat($res,$j,$i);
$rgbarray = imagecolorsforindex($res, $rgb);
if($rgbarray['red'] > 125 || $rgbarray['green']>125) {
$data[$i][$j]=1;
} else {
$data[$i][$j]=0;
}
}
}
return $data;
}
//显示生成的图片
function showNewPic() {
header('Content-type: image/jpeg');
ImageJPEG($this->img);
imagedestroy($this->img);
}
}

$captcha = new Captcha;
//$captcha->createZiMo();
$captcha->displayCaptcha();

验证码图片如下:

所在文件: http://www.onlypo.com/test/captcha/
查看demo: http://www.onlypo.com/test/captcha/captcha.php
...全文
247 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
帐篷专业户 2012-02-13
  • 打赏
  • 举报
回复
收下了,谢了!!!!!
码无边 2012-02-08
  • 打赏
  • 举报
回复
貌似楼主的程序可以借用下。
ghj902260 2012-02-06
  • 打赏
  • 举报
回复
!~
建议加背景

另外背景上最好有小小的英文字母。

这样会比较好一点!~
木目子 2012-02-02
  • 打赏
  • 举报
回复
http://code.google.com/p/cool-php-captcha
看看这个
daswcszxw 2012-02-02
  • 打赏
  • 举报
回复
不错。俺留着用了。
Gary-chen 2012-02-02
  • 打赏
  • 举报
回复
不错,我也收藏了
Gary-chen 2012-02-02
  • 打赏
  • 举报
回复
不错,我也收藏了
<img src="http://avatar.profile.csdn.net/A/1/7/2_crisdin.jpg" />
Crisdin 2012-02-02
  • 打赏
  • 举报
回复
如此类的资源应多多收集。以备不时之需啊。 3Q啦、
xiachao2008 2012-02-02
  • 打赏
  • 举报
回复
怎么破解………………
icelemon1314 2012-02-01
  • 打赏
  • 举报
回复
貌似一般变形加扭曲的验证码比较难识别出来...
bonlog 2012-02-01
  • 打赏
  • 举报
回复
行啊,不错啊,
我要走的路还很长。人外有人啊。
5月1日凌晨发布第一测试版 功能介绍: 1.生成中英文数字混合的字符串的字模数据. 2.可选择字体,大小,并且可独立调整文字的长和宽,生成任意形状的字符。 3.各种旋转,翻转文字功能 4.任意调整输出点阵大小,并任意调整字符在点阵中的位置。 5.字模数据输出可自定义各种格式,系统预设了C语言和汇编语言两种格式,并且可自己 定义出新的数据输出格式;每行输出数据个数可调。 6.支持四种取模方式:逐行(就是横向逐行取点),逐列(纵向逐列取点),行列(先 横向取第一行的8个点作为第一个字节,然后纵向取第二行的8个点作为第二个字节……), 列行(先纵向取第一列的前8个点作为第一个字节,然后横向取第二列的前8个点作为第二个 字节……) 7.支持阴码(亮点为1),阳码(亮点为0)取模 8.支持纵向(第一位为低位)(,倒向第一位为高位)取模 9.输出数制可选16进制或10进制 10.可生成索引文件,用于在生成的大量字库中可快速检索到需要的汉字 11.动态液晶面板彷真,可调节彷真面板象素点大小和颜色 12.图形模式下可任意用鼠标作画,左键画图,右键擦图。 12.旋转,翻转,平移等字符模式下的功能也可用与对BMP图象的处理 版本为pctolcd1.94 5月1日晚上发布第二测试版 更新如下: 1.增加锁定点阵大小功能,例如可锁定24X24点阵大小,然后调节独立调节字点阵的大小 2.增加热键功能,可用光标配合Ctrl,Shift对文字大小和位置修改 3.增加精简输出格式选项 4.把文字输入框换成了文字输入组合框,这样就可以保存历史纪录。 5.输出数据会自动清除以前的数据 6.可隐藏自定义格式,简化操作 7.一些小的BUG修正。 版本为pctolcd2.03 5月3日凌晨发布第三测试版 更新如下: 1.增加了一些小东西,例如演示动画一类的,我懒的一一写了 2.改掉一些可恶的小BUG,例如点阵输入框的自动完成。 3.增加大量文字处理和导入TXT文本文件功能,并且可以去除文本中的空白和重复字符, 可以对文本进行排序,适合于生成小字库。我这里测试是3万多字的TXT文件在2分钟内转成16X16点阵的字库文件。 版本号为pctolcd2.53 由于本软件侧重于对字符的处理,所以在图象方面功能较弱,请见晾。 5月8日发布正式版 正式版已经开始朝着液晶字库生成软件的方向进化了,我在后来的更新中把主要精力也放 在这部分,由于我目前还没有发现有同类的软件具备这个功能,也无法得到任何的参考,只能 自己摸索前进,所以如果还有不方便的地方请大家多提意见. 具体更新如下: 1.重写大部分的内核代码以配合汉字库生成的功能,目前这个内核已经进行了反复的测试, 相信稳定性和速度较前一版本有了巨大的提高. 2.去掉那个比较愚蠢的热键区了,因为用处不大 3.增加汉字库生成功能,这是最重要的改进之处,下文将详细介绍. 4.修正许多小BUG,使软件更加成熟些. 5月12日发布完美版 这次发布的PCtoLCD2002完美版与前一版本相比没有增加太多的功能,因为我觉得现有的这些功能已经足够用于生成各种字模的需要了,所以完美版的主要工作是反复测试,精心去除各种BUG,以及调节一些细微之处,目的当然就是追求完美!不过世上不会有真正完美的东西,这个软件也不例外,而且这个软件从头至尾全部是我一个人编写完成,精力有限,难免会顾此失彼,如果大家发现了这个版本中存在的BUG,请及时告诉我。 更新说明: 1。界面采用新的字体,不会再有那种难看的黑色粗体字,比以前的要漂亮多了。 2。加入全面的提示帮助,尽量减少普通用户的各种疑惑。 3。修正生成文件的扩展名的一些BUG,不会总是加上FON的扩展名了。 4。修正生成字模数据的一些格式BUG,现在生成的C51格式字模数据基本上可以直接粘贴到源程序中使用而不需要修改了 5。加入新的字模数据格式调整项,允许用户更自由的定制自己需要的数据格式 6。最重要的更新:全面支持保存当前设置功能,用户设置的字模格式,主窗口状态和字库生成窗口选项信息均可保存,下一次打开窗口时不用重新设置。 7。修正了新建图象时会自动跳到图形模式的BUG 8。增加输出紧凑格式数据选项,可以生成不包含空白行的字模数据。 9。完善了每行数据显示个数的功能,可以任意设置每行显示的数据个数,并同时可以设置每行索引数据显示个数。 10。修正了取模说明的一些错误,并改动了格式。 11。现在当用户选择10进制输出时,会自动去掉生成字模数据前的“0x",或后面的“H”,选择

20,398

社区成员

发帖
与我相关
我的任务
社区描述
“超文本预处理器”,是在服务器端执行的脚本语言,尤其适用于Web开发并可嵌入HTML中。PHP语法利用了C、Java和Perl,该语言的主要目标是允许web开发人员快速编写动态网页。
phpphpstorm 技术论坛(原bbs)
社区管理员
  • 开源资源社区
  • phpstory
  • xuzuning
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧