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

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
...全文
242 11 打赏 收藏 转发到动态 举报
写回复
用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
  • 打赏
  • 举报
回复
行啊,不错啊,
我要走的路还很长。人外有人啊。

20,360

社区成员

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

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