88646958@qq.com 发表于 2016-11-19 14:21:58

关于修改CI的的验证码captcha(3.1.2版)

本帖最后由 88646958@qq.com 于 2016-11-19 14:31 编辑

手册我们看到的验证码辅助函数,在我们生成验证码图片的时候实际上是一张png的图片,并且保存在了自己的配置目录里面。手册中提议说可以把验证码放进数据库,可是更多人可能愿意放进session里面。

综合上面两点可能有人就不愿意用这个验证码类了,然后就找找其他的验证码类来用。
其实我们可以扩展下这个captcha类,没用必要去弄些其他的验证类。而且我们扩展的这个类完全不比其他的差。
那我们来扩展下这个captcha验证码类。

如何修改?
首先我们遵循CI原则不破坏原始的类进行扩展,先system的helper复制captcha.php一份在自己的应用目录helper,然后重新命名MY_captcha_helper.php(当然MY_可以自己修改)

打开文件修改以下两处, 注释掉
大概在111行,图片存储的目录。

               if ($img_path === '' OR $img_url === ''
                        OR ! is_dir($img_path) OR ! is_really_writable($img_path)
                        OR ! extension_loaded('gd'))
                {
                        return FALSE;
                }

                // -----------------------------------
                // Remove old images
                // -----------------------------------

                $now = microtime(TRUE);

                $current_dir = @opendir($img_path);
                while ($filename = @readdir($current_dir))
                {
                        if (substr($filename, -4) === '.jpg' && (str_replace('.jpg', '', $filename) + $expiration) < $now)
                        {
                              @unlink($img_path.$filename);
                        }
                }

                @closedir($current_dir);


当然如果你需要把验证码生成的时间放到session里面那么$now = microtime(TRUE); 这个不要注释掉。
然后注释掉,图片生成的url地址。大概在336行

            $img_url = rtrim($img_url, '/').'/';

                if (function_exists('imagejpeg'))
                {
                        $img_filename = $now.'.jpg';
                        imagejpeg($im, $img_path.$img_filename);
                }
                elseif (function_exists('imagepng'))
                {
                        $img_filename = $now.'.png';
                        imagepng($im, $img_path.$img_filename);
                }
                else
                {
                        return FALSE;
                }

                $img = '<img '.($img_id === '' ? '' : 'id="'.$img_id.'"').' src="'.$img_url.$img_filename.'" style="width: '.$img_width.'; height: '.$img_height .'; border: 0;" alt=" " />';
               
然后在底部加上,大概像下面这样。
               header("Content-Type:image/png");      //加入图片格式header头
      imagepng($im);         
      ImageDestroy($im);
      return array('word' => $word , 'time' => $now /*,'image' => $img, 'filename' => $img_filename */);


这时候函数返回的是一个数组,我们把函数的返回值的 image和filename注释啊掉。我们只返回word和time两个值就可以了。如果不要时间 可以直接return $word
这里我们可以看到我们把图片存储的路径灭了,生成的图片地址也给灭了。这样我们可以把默认的两个必须的参数img_path,img_url变成不是必须的了。 其实咱们可以在函数里面直接把这两个参数也给灭掉。
大概像下面这样的

function create_captcha($data = '', /* $img_path = '', $img_url = '', */ $font_path = '')
      {
                $defaults = array(
                        'word'                => '',
                /*         'img_path'      => '',
                        'img_url'      => '', */
                        'img_width'      => '150',
                        'img_height'      => '30',
            .....



到此已经修改完毕。

如何使用?
在控制器,大概下面这样,看代码
                     
public function captcha()
      {
         $this->load->library('session');
         $this->load->helper('captcha');
            $vals = array(
                        'word'         => rand_chr(6), // 这里用了自己的随机字符串库。
                        'font_path'    => BASEPATH.'fonts/DetailBETA.ttf', // 定义自己的验证码字体
                        'img_width'    => '150',
                        'img_height'   => 39,
                        'expiration'   => 300,
                        'word_length'=> 8,
                        'font_size'    => 16,
                        'colors'       => array(
                                                'background' => array(255, 255, 255),
                                                'border'   => array(255, 255, 255),
                                                'text'       => array(40, 40, 40),
                                                'grid'       => array(255, 40, 40)
                                                                   )
                     );
                $cap = create_captcha($vals);
                $this->session->set_userdata('code', $cap);//如果只存验证码 到session 用$cap['word'] ,此处存进session的是数组。

    }

然后可以自己测试下。在浏览器地址输出 http://localhost/ci/index.php/控制器/captcha 就可以看到漂亮的验证码了。这里要配置好你自己的session, 然后我们在session目录可以看到自己存进去的验证码信息了。
我们打开session的存储目录打开session文件可以看到类似下面这样的东西
__ci_last_regenerate|i:1479522546;code|a:2:{s:4:"word";s:6:"3L2TPH";s:4:"time";d:1479522549.0557859;}
当然如果你喜欢默认的,完全可以自己配置你任何你喜欢的验证码。当然如果你不喜欢默认的字符串,你可以用自己的字符串库 。这里用了rand_chr(), 当你配置了 'word'后 'word_length'就不生效了。
下面是自己写的一个随机字符串函数,我把放进captcha扩展里面,其实遵循CI原则,应该尽量在字符串副主函数里面扩展,这里偷简单就直接放在captcha扩展里面了。

if ( ! function_exists('rand_chr'))
{

      function rand_chr($length)
      {
                $str = '234578ZYACEFGHJKLMNPRSTUVW';//自己定义喜欢的字符串
                $str = str_shuffle($str);
                return substr($str,0,$length);
      }

}

接下来怎么读验证码

         $this->session->code['word'];
         $this->session->code['time'];//如果你要读取验证码生成存储的时间

在登录控制器我们在填写的验证码和 到session里面读取的验证码进行比较, 就可以这样使用了。
是不是这样扩展后用起来就很爽了!!!
总结:
我个人认为CI 默认的验证码类其实是最安全有效的。个人推荐不要修改,直接用默认的即使麻烦了点。



88646958@qq.com 发表于 2016-11-19 15:12:18

:victory::lol

ASEN 发表于 2018-6-16 17:03:29

给力
页: [1]
查看完整版本: 关于修改CI的的验证码captcha(3.1.2版)