FreeIdea

导航

CakePHP Components -- CAPTCHA

这是我以前写的一个CAPTCHA(FOR CakePHP)组件, 也在也一直在用。

如果大家喜欢并使用了这个组件,请给我发封邮件: aeon[at]apsou.com

 

 

 组件代码:

  1 class CaptchaComponent extends Object {
  2     private $controller;
  3     private $fonts;
  4     private $length = 6;
  5     
  6     public $caseSensitive = false;
  7     public $noise = 0;
  8     public $blur  = 0;
  9     /**
 10      * numeric | alpha | alphanumeric
 11      **/
 12     public $type  = 'numeric';
 13     
 14     public $components = array('RequestHandler');
 15     
 16     public function startup(&$controller) {
 17         if (!class_exists('Folder')) {
 18             App::import('Core', 'Folder');
 19         }
 20         $this->controller = $controller;
 21         $fontpath = WWW_ROOT . 'files' . DS . 'fonts';
 22         $folder = new Folder($fontpath);
 23         if (false === $folder) {
 24             trigger_error('字体目录 files/fonts 不存在.');
 25             exit;
 26         }
 27         $fonts = $folder->find('.+\.ttf');
 28         if (empty($fonts|| !is_array($fonts)) {
 29             trigger_error('字体目录 files/fonts 中没有正确的字体文件(*.ttf).');
 30             exit;
 31         }
 32         foreach($fonts as &$font) {
 33             $font = $fontpath . DS . $font;
 34         }
 35         $this->fonts = $fonts;
 36         unset($fontpath, $fonts);
 37     }
 38     
 39     /**
 40      * @param array $params
 41      **/
 42     public function create($model) {
 43         if (!is_string($model)) return false;
 44         $words = $this->__wordsGen();
 45         /**
 46          * 写入
 47          **/
 48         $this->controller->Session->write('CAPTCHA_WORDS', $words);
 49         $this->controller->Session->write('CAPTCHA_MODEL', $model);
 50         $this->noise = abs($this->noise);
 51         $this->blur = abs($this->blur);
 52         $this->__makeCaptcha($words);
 53         $this->controller->autoRender = false;
 54     }
 55     
 56     public function isValid($field = 'captcha') {
 57         if (true === $this->RequestHandler->isPost()) {
 58             $words = $this->controller->Session->check('CAPTCHA_WORDS'? $this->controller->Session->read('CAPTCHA_WORDS': false;
 59             $model = $this->controller->Session->check('CAPTCHA_MODEL'? $this->controller->Session->read('CAPTCHA_MODEL': false;
 60             if (false === $words || false === $model) {
 61                 return false;
 62             }
 63             if (isset($this->controller->data[$model][$field]) &&
 64                 !empty($this->controller->data[$model][$field])) {
 65                 $input = $this->controller->data[$model][$field];
 66                 if (true !== $this->caseSensitive) {
 67                     $input = strtolower($input);
 68                     $words = strtolower($words);
 69                 }
 70                 $result = strcmp($input, $words=== 0;
 71                 if (true === $result) {
 72                     $this->controller->Session->del('CAPTCHA_WORDS');
 73                     $this->controller->Session->del('CAPTCHA_MODEL');
 74                     unset($this->controller->data[$model][$field]);
 75                     return true;
 76                 }
 77             }
 78             return false;
 79         }
 80         return false;
 81     }
 82     
 83     private function __getRandFonts () {
 84         return $this->fonts[mt_rand(0, count($this->fonts) - 1)];
 85     }
 86     
 87     /**
 88      * 生成随机字符串
 89      **/
 90     private function __wordsGen() {
 91         $results   = null;
 92         
 93         switch($this->type) {
 94             case 'numeric' : $charPool = range(0, 9); break;
 95             case 'alpha'   : $charPool = range('A', 'Z'); break;
 96             default   : $charPool = array_merge(range('A', 'Z'), range(1, 9)); break;
 97         }
 98         
 99         if ($this->type !== 'numeric') {
100             if ($this->caseSensitive) {
101                 $lowercase  = range('a', 'z');
102                 $charPool   = array_merge($charPool, $lowercase);
103             }
104         }
105         
106         $poolLength = count($charPool- 1;
107         
108         for ($i = 0$i < $this->length; $i++) {
109             $results .= $charPool[mt_rand(0, $poolLength)];
110         }
111         
112         return $results
113     }
114     
115     /**
116      * 将文字添加到画板
117      **/
118     private function __signs(&$image, $font, $cells = 3) {
119         $w = imagesx($image);
120         $h = imagesy($image);
121         
122         for ($i = 0$i < $cells$i++) {
123             $centerX     = mt_rand(1, $w);
124             $centerY     = mt_rand(1, $h);
125             $amount      = mt_rand(1, 15);
126             $stringcolor = imagecolorallocate($image, 200, 200, 200);
127             for ($n = 0$n < $amount$n++) {
128                 $signs = range('A', 'Z');
129                 $sign  = $signs[mt_rand(0, count($signs- 1)];
130                 imagettftext($image, 25,
131                              mt_rand(-15, 15),
132                              $centerX + mt_rand(-50, 50),
133                              $centerY + mt_rand(-50, 50),
134                              $stringcolor, $font, $sign);
135             }
136         }
137     }
138     
139     /**
140      * 添加嗓点
141      **/
142     private function __noise(&$image, $runs = 30) {
143         $w = imagesx($image);
144         $h = imagesy($image);
145         for ($n = 0$n < $runs$n++) {
146             for ($i = 1$i <= $h$i++) {
147                 $randcolor = imagecolorallocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
148                 imagesetpixel($image, mt_rand(1, $w), mt_rand(1, $h), $randcolor);
149             }
150         }  
151     }
152     
153     /**
154      * 模糊
155      **/
156     private function __blur (&$image, $radius = 3) {
157         $radius  = round(max(0, min($radius, 50)) * 2);
158         $w       = imagesx($image);
159         $h       = imagesy($image);
160         $imgBlur = imagecreate($w, $h);
161         for ($i = 0$i < $radius$i++) {
162             imagecopy     ($imgBlur, $image,   0, 0, 1, 1, $w - 1, $h - 1);
163             imagecopymerge($imgBlur, $image,   1, 1, 0, 0, $w,     $h,     50.0000);
164             imagecopymerge($imgBlur, $image,   0, 1, 1, 0, $w - 1, $h,     33.3333);
165             imagecopymerge($imgBlur, $image,   1, 0, 0, 1, $w,     $h - 1, 25.0000);
166             imagecopymerge($imgBlur, $image,   0, 0, 1, 0, $w - 1, $h,     33.3333);
167             imagecopymerge($imgBlur, $image,   1, 0, 0, 0, $w,     $h,     25.0000);
168             imagecopymerge($imgBlur, $image,   0, 0, 0, 1, $w,     $h - 1, 20.0000);
169             imagecopymerge($imgBlur, $image,   0, 1, 0, 0, $w,     $h,     16.6667);
170             imagecopymerge($imgBlur, $image,   0, 0, 0, 0, $w,     $h,     50.0000);
171             imagecopy     ($image  , $imgBlur, 0, 0, 0, 0, $w,     $h);
172         }
173         imagedestroy($imgBlur);
174     }
175     
176     private function __makeCaptcha($words) {
177         $imagelength = $this->length * 25 + 16;
178         $imageheight = 55;
179         $image       = imagecreate($imagelength, $imageheight);
180         $bgcolor     = imagecolorallocate($image, 255, 255, 255);
181         
182         $this->__signs($image, $this->__getRandFonts());
183         
184         for ($i = 0$i < $this->length; $i++) {
185             $stringcolor = imagecolorallocate($image, rand(0, 170), rand(0, 170), rand(0, 170));
186             imagettftext($image, 25, mt_rand(-15, 15), $i * 25 + 10, mt_rand(30, 50), $stringcolor, $this->__getRandFonts(), $words[$i]);
187         }
188         
189         if ($this->noise > 0) {
190             $this->__noise($image, $this->noise);
191         }
192         if ($this->blur > 0) {
193             $this->__blur($image, $this->blur);
194         }
195         
196         header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
197         header('Last-Modified: ' . gmdate('D, d M Y H:i:s'. 'GMT');
198         header('Cache-Control: no-cache, must-revalidate');
199         header('Pragma: no-cache');
200         header('Content-type: image/png');
201         imagepng($image);
202         imagedestroy($image);
203     }
204 }
205 ?>

 

应用:

在控制器中, 比如 UsersController


 1class UsersController extends AppController {
 2
 3     .
 4
 5    public $components = array('Captcha');
 6    
 7    public function captcha($modelName = 'User') {
 8        $modelName = Inflector::camelize($modelName);
 9        $this->autoRender = false;
10        $this->Captcha->noise = 5;              //嗓点
11        $this->Captcha->blur = 0;               //模糊效果级别, 0为不使用模糊
12        $this->Captcha->type = 'alpha';         //numeric | alpha | alphpnumeric
13        $this->Captcha->caseSensitive = false;  //是否区分大小写, 只在非纯数字情况下有效
14        $this->Captcha->create($modelName);         //创建
15    }
16
17 
18
19    public function login() {
20
21        if (!empty($this->data)) {
22            if ($this->Captcha->isValid()) {
23                if ($this->User->verify($this->data)) {
24                   .
25                }
26            } else {
27                $this->Session->setFlash('验证码错误, 请重新输入.');
28            }
29        }
30
31    }     .
32
33}

 

在 view :(users/login.ctp)

1 <?php echo $html->image('/users/captcha/user', array('id' => 'captcha_image')); ?><span class="explain">不区分大小写. 如果看不清楚, 请<a href="javascript:reloadCAPTCHA();">换一张</a>再试.</a>
2<script type="text/javascript">
3function reloadCAPTCHA() {
4    var img = $('captcha_image');
5    if (img && img.src != undefined) {
6        img.src = '/users/captcha/user/' + Math.random(1000, 9999);
7    }
8}
9</script>

posted on 2009-06-09 15:16  aeon  阅读(817)  评论(0编辑  收藏  举报