作者:
彭勇 | 时间:2012-4-25 | | 49 Views
<?php
/**
**/
class YL_Security_Secoder {
//验证码的session的下标
public static $seKey = 'verify_py'; //验证码关键字
public static $expire = 3000; // 验证码过期时间(s)
//验证码中使用的字符,01IO容易混淆,不用
//public static $codeSet = '3456789ABCDEFGHJKLMNPQRTUVWXY';
public static $codeSet = array('一','二','三','四','五','六','七','八','九');
public static $fontSize = 26; // 验证码字体大小(px)
public static $useCurve = true; // 是否画混淆曲线
public static $useNoise = true; // 是否添加杂点
public static $imageH = 0; // 验证码图片宽
public static $imageL = 0; // 验证码图片长
public static $length = 4; // 验证码位数
public static $bg = array(200, 255, 255); // 背景
public static $rotateAngle=45;
public static $offset=1;
public static $padding_left=10;
protected static $_image = null; // 验证码图片实例
protected static $_color = null; // 验证码字体颜色
private static $noiseArr=array(3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,T,U,V,W,X,Y);
private static function init()
{
shuffle(self::$codeSet);
}
/**
* 输出验证码并把验证码的值保存的session中
*/
public static function entry() {
self::init();//初始化
// 图片宽(px)
self::$imageL || self::$imageL = self::$length * self::$fontSize * 1.5 + self::$fontSize*1.5;
// 图片高(px)
self::$imageH || self::$imageH = self::$fontSize * 2;
// 建立一幅 self::$imageL x self::$imageH 的图像
self::$_image = imagecreate(self::$imageL, self::$imageH);
// 设置背景
imagecolorallocate(self::$_image, self::$bg[0], self::$bg[1], self::$bg[2]);
// 验证码字体随机颜色
self::$_color = imagecolorallocate(self::$_image, mt_rand(1,120), mt_rand(1,120), mt_rand(1,120));
// 验证码使用随机字体,保证目录下有这些字体集
//$ttf = dirname(__FILE__) . '/ttfs/t' . mt_rand(1, 1) . '.ttf';
$ttf = dirname(__FILE__) . '/ttfs/t9.ttf';
//exit($ttf);
if (self::$useNoise) {
// 绘杂点
self::_writeNoise();
}
if (self::$useCurve) {
// 绘干扰线
self::_writeCurve();
}
// 绘验证码
$code = array(); // 验证码
$codeNX = 0; // 验证码第N个字符的左边距
$tmpSourceArrLen=count(self::$codeSet)-1;
//echo "tmpSourceArrLen=".$tmpSourceArrLen ;
//exit();
for ($i = 0; $i<self::$length; $i++) {
$code[$i] = self::$codeSet[$i];
//var_dump ($code[$i]);
//$code[$i]=iconv("GB2312","UTF-8",$code[$i]) ;
//exit();
// $codeNX += mt_rand(self::$fontSize*1.2, self::$fontSize*1.2);
//$codeNX = $i===0?self::$offset:($i)*(self::$fontSize)-self::$padding_left ;
$codeNX=(self::$fontSize-self::$offset)*$i+self::$padding_left;
imagettftext(self::$_image, self::$fontSize,self::$rotateAngle, $codeNX, self::$fontSize*1.5, self::$_color, $ttf, $code[$i]);
}
// 保存验证码
isset($_SESSION) || session_start();
$_SESSION[self::$seKey]['code'] = join('', $code); // 把验证码保存到session, 验证时注意是大写
$_SESSION[self::$seKey]['time'] = time(); // 验证码创建时间
header('Pragma: no-cache');
header("content-type: image/JPEG");
// 输出图像
imageJPEG(self::$_image);
imagedestroy(self::$_image);
}
/**
* 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数)
* 正弦型函数解析式:y=Asin(ωx+φ)+b
* 各常数值对函数图像的影响:
* A:决定峰值(即纵向拉伸压缩的倍数)
* b:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
* φ:决定波形与X轴位置关系或横向移动距离(左加右减)
* ω:决定周期(最小正周期T=2π/∣ω∣)
*/
protected static function _writeCurve() {
$A = mt_rand(1, self::$imageH/2); // 振幅
$b = mt_rand(-self::$imageH/4, self::$imageH/4); // Y轴方向偏移量
$f = mt_rand(-self::$imageH/4, self::$imageH/4); // X轴方向偏移量
$T = mt_rand(self::$imageH*1.5, self::$imageL*2); // 周期
$w = (2* M_PI)/$T;
$px1 = 0; // 曲线横坐标起始位置
$px2 = mt_rand(self::$imageL/2, self::$imageL * 0.667); // 曲线横坐标结束位置
for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
if ($w!=0) {
$py = $A * sin($w*$px + $f)+ $b + self::$imageH/2; // y = Asin(ωx+φ) + b
$i = (int) ((self::$fontSize - 6)/4);
while ($i > 0) {
imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color);
//这里画像素点比imagettftext和imagestring性能要好很多
$i--;
}
}
}
$A = mt_rand(1, self::$imageH/2); // 振幅
$f = mt_rand(-self::$imageH/4, self::$imageH/4); // X轴方向偏移量
$T = mt_rand(self::$imageH*1.5, self::$imageL*2); // 周期
$w = (2* M_PI)/$T;
$b = $py - $A * sin($w*$px + $f) - self::$imageH/2;
$px1 = $px2;
$px2 = self::$imageL;
for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
if ($w!=0) {
$py = $A * sin($w*$px + $f)+ $b + self::$imageH/2; // y = Asin(ωx+φ) + b
$i = (int) ((self::$fontSize - 8)/4);
while ($i > 0) {
imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color);
//这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出
//的(不用while循环)性能要好很多
$i--;
}
}
}
}
/**
* 画杂点
* 往图片上写不同颜色的字母或数字
*/
protected static function _writeNoise() {
for($i = 0; $i < 10; $i++){
//杂点颜色
$noiseColor = imagecolorallocate(
self::$_image,
mt_rand(120,225),
mt_rand(120,225),
mt_rand(120,225)
);
for($j = 0; $j < 5; $j++) {
// 绘杂点
imagestring(
self::$_image,
5,
mt_rand(-10, self::$imageL),
mt_rand(-10, self::$imageH),
self::$noiseArr[mt_rand(0, 28)], // 杂点文本为随机的字母或数字
$noiseColor
);
}
}
}
/**
* 验证验证码是否正确
*
* @param string $code 用户验证码
* @param bool 用户验证码是否正确
*/
public static function check($code) {
isset($_SESSION) || session_start();
// 验证码不能为空
if(empty($code) || empty($_SESSION[self::$seKey])) {
return false;
}
// session 过期
if(time() - $_SESSION[self::$seKey]['time'] > self::$expire) {
unset($_SESSION[self::$seKey]);
return false;
}
if(strcasecmp($_SESSION[self::$seKey]['code'], trim($_POST['checkcode']))==0)
{
return true;
}
return false;
}
}
?>
index.php
<?php
mb_internal_encoding("utf-8");
include "verify.class.php";
//调用上面定义的验证码类 来生产验证码
YL_Security_Secoder::$fontSize=18;
YL_Security_Secoder::$imageL=100;
YL_Security_Secoder::$imageH=30;
$is_cn=true || false;//中文还是英文
if($is_cn)
{
//中文
$chineseDictStr="从明天起做一个幸福的人喂马劈柴周游世界从明天起关心粮食和蔬菜我有一所房子面朝大海春暖花开从明天起和每一个亲人通信告诉他们我的幸福那幸福的闪电告诉我的我将告诉每一个人给每一条河每一座山取一个温暖的名字陌生人我也为你祝福愿你有一个灿烂的前程愿你有情人终成眷属愿你在尘世获得幸福我只愿面朝大海春暖花开";
$chineseArr=mb_str_split( $chineseDictStr ); //得到字符串
//如果不考虑重复,下面三条可以注释,
$chineseArr=array_unique($chineseArr);//去重复
$chineseArr=array_values($chineseArr);//重新索引
$chineseArr=getUniqueItem($chineseArr,YL_Security_Secoder::$length);//获取指定长度不重复字符串
YL_Security_Secoder::$codeSet=$chineseArr;//
}
else
{
//英文
YL_Security_Secoder::$codeSet=mb_str_split('3456789ABCDEFGHJKLMNPQRTUVWXY');
YL_Security_Secoder::$offset=8;
YL_Security_Secoder::$imageL=60;
}
YL_Security_Secoder::$rotateAngle=mt_rand(-10, 20);
//$randBgR=mt_rand(0,243);
//YL_Security_Secoder::$bg=array($randBgR, 251, 254); // 背景
YL_Security_Secoder::$useNoise = true; //是否启用噪点
YL_Security_Secoder::$useCurve = false; //是否启用干扰曲线
YL_Security_Secoder::entry();
function mb_str_split( $string ) {
# Split at all position not after the start: ^
# and not before the end: $
return preg_split('/(?<!^)(?!$)/u', $string );
}
// $string = '火车票';
// $charlist = mb_str_split( $string );
function getUniqueItem($array,$len)
{
if(! is_array($array)|| (count($array)<1) || ($len <1))
{
return array();
}
$tmpArr=array();
$arrLen=count($array);
for($i=0;$i<$len;$i++)
{
$randNum=mt_rand(0,$arrLen-1);
$tmpArr[]=$array[$randNum];
$array[$randNum]=$array[$arrLen-1];
array_pop($array);
$arrLen--;
}
return $tmpArr;
}
?>
演示地址:demo