既简单又安全的PHP验证码 附调用方法


Posted in PHP onJune 02, 2016

一、验证码示例

既简单又安全的PHP验证码 附调用方法

二、php验证码类,secoder.class.php

<?php 
/** 
 * 安全验证码 
 * 
 * 安全的验证码要:验证码文字扭曲、旋转,使用不同字体,添加干扰码 
 * 
 * @author 流水孟春 <cmpan(at)qq.com> 
 * @link http://labs.yulans.cn/YL_Security_Secoder 
 * @link http://wiki.yulans.cn/docs/yl/security/secoder 
 */ 
class YL_Security_Secoder { 
  /** 
   * 验证码的session的下标 
   * 
   * @var string 
   */ 
  //public static $seKey = 'sid.sek ey.ylans.cn'; 
  public static $seKey = 'sid'; 
  public static $expire = 3000;   // 验证码过期时间(s) 
  /** 
   * 验证码中使用的字符,01IO容易混淆,建议不用 
   * 
   * @var string 
   */ 
  public static $codeSet = '346789ABCDEFGHJKLMNPQRTUVWXY'; 
  public static $fontSize = 25;   // 验证码字体大小(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(243, 251, 254); // 背景 
   
  protected static $_image = null;   // 验证码图片实例 
  protected static $_color = null;   // 验证码字体颜色 
   
  /** 
   * 输出验证码并把验证码的值保存的session中 
   * 验证码保存到session的格式为: $_SESSION[self::$seKey] = array('code' => '验证码值', 'time' => '验证码创建时间'); 
   */ 
  public static function entry() { 
    // 图片宽(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/' . mt_rand(1, 20) . '.ttf'; 4 
    $ttf = dirname(__FILE__) . '/ttfs/4.ttf';  
     
    if (self::$useNoise) { 
      // 绘杂点 
      self::_writeNoise(); 
    }  
    if (self::$useCurve) { 
      // 绘干扰线 
      self::_writeCurve(); 
    } 
     
    // 绘验证码 
    $code = array(); // 验证码 
    $codeNX = 0; // 验证码第N个字符的左边距 
    for ($i = 0; $i<self::$length; $i++) { 
      $code[$i] = self::$codeSet[mt_rand(0, 27)]; 
      $codeNX += mt_rand(self::$fontSize*1.2, self::$fontSize*1.6); 
      // 写一个验证码字符 
      imagettftext(self::$_image, self::$fontSize, mt_rand(-40, 70), $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('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate'); 
    header('Cache-Control: post-check=0, pre-check=0', false);    
    header('Pragma: no-cache');    
    header("content-type: image/png"); 
   
    // 输出图像 
    imagepng(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(150,225),  
               mt_rand(150,225),  
               mt_rand(150,225) 
             ); 
      for($j = 0; $j < 5; $j++) { 
        // 绘杂点 
        imagestring( 
          self::$_image, 
          5,  
          mt_rand(-10, self::$imageL),  
          mt_rand(-10, self::$imageH),  
          self::$codeSet[mt_rand(0, 27)], // 杂点文本为随机的字母或数字 
          $noiseColor 
        ); 
      } 
    } 
  } 
   
  /** 
   * 验证验证码是否正确 
   * 
   * @param string $code 用户验证码 
   * @param bool 用户验证码是否正确 
   */ 
  public static function check($code) { 
    isset($_SESSION) || session_start(); 
    // 验证码不能为空 
    if(empty($code) || empty($_SESSION[self::$seKey])) { 
      //echo $_SESSION[self::$seKey]['code'].'1'; 
      return false; 
           
    } 
    // session 过期 
    if(time() - $_SESSION[self::$seKey]['time'] > self::$expire) { 
      unset($_SESSION[self::$seKey]); 
      //echo $_SESSION[self::$seKey]['code'].'2'; 
      return false; 
      //return 0; 
    } 
 
//   if($code == $_SESSION[self::$seKey]['code']) { 
    if(strtoupper($code) == $_SESSION[self::$seKey]['code']) { //不区分大小写比较 
      //echo $_SESSION[self::$seKey]['code'].'3'; 
      return true;     
    } 
    //echo $_SESSION[self::$seKey]['code'].'4'; 
    return false; 
         
  } 
} 
 
 
// useage 
/* 
YL_Security_Secoder::$useNoise = false; // 要更安全的话改成true 
YL_Security_Secoder::$useCurve = true; 
YL_Security_Secoder::entry(); 
*/ 
 
/* 
// 验证验证码 
if (!YL_Security_Secoder::check(@$_POST['secode'])) { 
  print 'error secode'; 
} 
*/

三、调用方法

1、显示验证码页面code.php

<?php  
  session_start(); 
  require 'secoder.class.php'; //先把类包含进来,实际路径根据实际情况进行修改。  
  $vcode = new YL_Security_Secoder();   //实例化一个对象  
  $vcode->entry();  
?>

2、检查验证码是否正确

<?php  
  session_start(); 
  require 'secoder.class.php'; //先把类包含进来,实际路径根据实际情况进行修改。  
  $vcode = new YL_Security_Secoder();   //实例化一个对象  
  //$vcode->entry();  
  $code = $_GET['code'];  
  echo $vcode->check($code);     
  //$_SESSION['code'] = $vc->getCode();//验证码保存到SESSION中 
?>

3、验证码输入框调用页面

<img id="messageImg" src='images/tishis2.gif' width='16' height='16'> 单击图片重新获取验证码<br> 
<a href="#"><img src="code.php" onclick="javascript:this.src='code.php?tm='+Math.random();" />

以上就是本文的全部内容,希望对大家学习PHP程序设计有所帮助。

PHP 相关文章推荐
怎么样可以把 phpinfo()屏蔽掉?
Nov 24 PHP
php巧获服务器端信息
Dec 06 PHP
phpMyAdmin 安装配置方法和问题解决
Jun 08 PHP
joomla内置的表单验证功能使用方法
Jun 11 PHP
php结合ajax实现赞、顶、踩功能实例
May 12 PHP
用 Composer构建自己的 PHP 框架之构建路由
Oct 30 PHP
php使用gettimeofday函数返回当前时间并存放在关联数组里
Mar 19 PHP
Linux操作系统安装LAMP环境
Jun 26 PHP
php实现网站顶踩功能的完整前端代码
Jul 19 PHP
php curl获取https页面内容,不直接输出返回结果的设置方法
Jan 15 PHP
PHP根据key删除数组中指定的元素
Feb 28 PHP
PHP使用反向Ajax技术实现在线客服系统详解
Jul 01 PHP
yii2分页之实现跳转到具体某页的实例代码
Jun 02 #PHP
[原创]php实现子字符串位置相互对调互换的方法
Jun 02 #PHP
PHP处理数组和XML之间的互相转换
Jun 02 #PHP
PHP邮箱验证示例教程
Jun 01 #PHP
PHP微信公众号自动发送红包API
Jun 01 #PHP
PHP模块化安装教程
Jun 01 #PHP
深入理解PHP之源码目录结构与功能说明
Jun 01 #PHP
You might like
判断是否为指定长度内字符串的php函数
2010/02/16 PHP
zend api扩展的php对象的autoload工具
2011/04/18 PHP
php语言流程控制中的主动与被动
2012/11/05 PHP
PHP封装的验证码工具类定义与用法示例
2018/08/22 PHP
php图像生成函数之间的区别分析
2012/12/06 Javascript
ajax中get和post的说明及使用与区别
2012/12/23 Javascript
$.get获取一个文件的内容示例代码
2013/09/11 Javascript
JS实现点击文字对应DIV层不停闪动效果的方法
2015/03/02 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
BootStrap无限级分类(无限极分类封装版)
2016/08/26 Javascript
bootstrap的工具提示实例代码
2017/05/17 Javascript
微信小程序 sha1 实现密码加密实例详解
2017/07/06 Javascript
详解vue-cli项目中用json-sever搭建mock服务器
2017/11/02 Javascript
详解Js里的for…in和for…of的用法
2019/03/28 Javascript
javascript实现的时间格式加8小时功能示例
2019/06/13 Javascript
[53:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第一场 1月31日
2021/03/11 DOTA
Python常见文件操作的函数示例代码
2011/11/15 Python
python实现挑选出来100以内的质数
2015/03/24 Python
Python读写unicode文件的方法
2015/07/10 Python
Python实现多线程抓取妹子图
2015/08/08 Python
django上传图片并生成缩略图方法示例
2017/12/11 Python
Python异常对代码运行性能的影响实例解析
2018/02/08 Python
python 判断参数为Nonetype类型或空的实例
2018/10/30 Python
python多个模块py文件的数据共享实例
2019/01/11 Python
python算法与数据结构之单链表的实现代码
2019/06/27 Python
Python字符串处理的8招秘籍(小结)
2019/08/13 Python
Pandas操作CSV文件的读写实现方法
2019/11/13 Python
python logging添加filter教程
2019/12/24 Python
在django中form的label和verbose name的区别说明
2020/05/20 Python
高职助产应届生自荐信
2013/09/24 职场文书
护理学中专毕业生求职信
2013/11/11 职场文书
企业人事任命书
2014/06/05 职场文书
2015年小学开学寄语
2015/02/27 职场文书
学校标语口号大全
2015/12/26 职场文书
解决tk mapper 通用mapper的bug问题
2021/06/16 Java/Android
mysql 生成连续日期及变量赋值
2022/03/20 MySQL