root/trunk/system/libraries/Captcha.php

Revision 3010, 10.4 kB (checked in by Geert, 6 hours ago)

Cleaning up Captcha_Controller. Using in built in text::random() function. No more special characters, like $ or %, in captcha's anymore. Just a-z0-9.

  • Property svn:eol-style set to LF
  • Property copyright set to Copyright (c) 2008 Kohana Team
  • Property svn:keywords set to Id
Line 
1 <?php defined('SYSPATH') or die('No direct script access.');
2 /**
3  * Captcha library.
4  *
5  * $Id$
6  *
7  * @package    Core
8  * @author     Kohana Team
9  * @copyright  (c) 2007-2008 Kohana Team
10  * @license    http://kohanaphp.com/license.html
11  */
12 class Captcha_Core {
13
14     // Config
15     protected $font_path        = '';
16     protected $font_name        = '';
17     protected $width            = 150;
18     protected $height           = 50;
19     protected $background_image = '';
20     protected $style            = 'basic';
21     protected $num_chars        = 4;
22
23     // Class internal variables
24     protected $image;
25     protected $color_black;
26     protected $color_white;
27     protected $spacing;
28     protected $captcha_code;
29     protected $numerals = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
30
31     /**
32      * Creates a new Captcha instance.
33      *
34      * @throws  Kohana_Exception
35      * @param   array  configuration
36      * @return  void
37      */
38     public function __construct($config = array())
39     {
40         static $check;
41
42         // Check that a suitable GD2 library is available
43         ($check === NULL) and $check = function_exists('imagegd2');
44
45         if ($check === FALSE)
46             throw new Kohana_Exception('captcha.requires_GD2');
47
48         // Load configuration
49         $config += Config::item('captcha', FALSE, FALSE);
50
51         $this->initialize($config);
52
53         // If using a background image, check if it exists.
54         if ($this->background_image)
55         {
56             if ( ! file_exists($this->background_image))
57                 throw new Kohana_Exception('captcha.file_not_found', $this->background_image);
58         }
59
60         // If using a font, check if it exists.
61         if ($this->font_name)
62         {
63             if ( ! file_exists($this->font_path.$this->font_name))
64                 throw new Kohana_Exception('captcha.file_not_found', $this->font_path.$this->font_name);
65         }
66
67         Log::add('debug', 'Captcha Library initialized');
68     }
69
70     /**
71      * Sets or overwrites config values.
72      *
73      * @param   array  configuration
74      * @return  void
75      */
76     public function initialize($config)
77     {
78         // Assign config values to the object
79         foreach ($config as $key => $value)
80         {
81             if (property_exists($this, $key))
82             {
83                 $this->$key = $value;
84             }
85         }
86     }
87
88     /**
89      * Sets the Captcha code to use.
90      *
91      * @param   string  captcha code generated in captcha controller
92      * @return  void
93      */
94     public function set_code($str)
95     {
96         $this->captcha_code = (string) $str;
97     }
98
99     /**
100      * Generates the Captcha image.
101      *
102      * @return  void
103      */
104     public function render()
105     {
106         // If extending the class with a custom Captcha function, name it 'xyz_captcha'.
107         // Style 'xyz' must be added to config. Now call the method that implements the Captcha.
108         $this->{$this->style.'_captcha'}();
109
110         // Tell browser what to expect
111         // TODO: make this automatic
112         // header('Content-Type: image/jpeg');
113         header('Content-Type: image/png');
114
115         // Output the captcha image
116         // imagejpeg($this->image);
117         imagepng($this->image);
118
119         // Free up resources
120         imagedestroy($this->image);
121     }
122
123     /**
124      * Validates the Captcha code against session Captcha code
125      *
126      * @param   string   captcha code text
127      * @return  boolean
128      */
129     public static function valid_captcha($str)
130     {
131         return (strtoupper($str) === strtoupper(Session::instance()->get('captcha_code')));
132     }
133
134     /**
135      * Creates image resource and allocates some basic colors.
136      * If a background image is supplied, the image dimensions are used.
137      *
138      * @return  void
139      */
140     protected function img_create()
141     {
142         if ($this->background_image)
143         {
144             // TODO: create from any valid image
145             $this->image = imagecreatefromjpeg($this->background_image);
146             $this->color_white = imagecolorallocate($this->image, 255, 255, 255);
147
148             // Get the background image dimensions
149             $this->width  = imagesx($this->image);
150             $this->height = imagesy($this->image);
151         }
152         else
153         {
154             $this->image = imagecreatetruecolor($this->width, $this->height);
155             $this->color_white = imagecolorallocate($this->image, 255, 255, 255);
156
157             // Fill the image with a colored gradient (use random colors, but try not to obscure text)
158             $left_color  = array(mt_rand(100,255), 0, 255);
159             $right_color = array(100, 100, mt_rand(100,0));
160             $this->img_color_gradient($this->image, 0, 0, $this->height, $this->width, $left_color, $right_color);
161         }
162     }
163
164     /**
165      * Allocates a background color to image.
166      *
167      * @param   array  GD image color identifier
168      * @return  void
169      */
170     protected function img_background($color)
171     {
172         imagefill($this->image, 0, 0, $color);
173     }
174
175     /**
176      * Draws a very basic Captcha image.
177      * Requires only GD. Useful for testing or if you can't use truetype fonts.
178      *
179      * @return  void
180      */
181     protected function basic_captcha()
182     {
183         $this->image       = imagecreate($this->width, $this->height);
184         $this->color_white = imagecolorallocate($this->image, 255, 255, 255);
185         $this->color_black = imagecolorallocate($this->image, 0, 0, 0);
186
187         imagestring($this->image, 5, 50, 15, $this->captcha_code, $this->color_black);
188     }
189
190     /**
191      * Draws the standard Captcha image:
192      * Requires GD with freetype and available truetype compatible font files.
193      *
194      * @param   none
195      * @return  void
196      */
197     protected function standard_captcha()
198     {
199         $this->img_create();
200
201         $font = $this->font_path.$this->font_name;
202         $this->calculate_spacing();
203
204         // Draw each Captcha character with varying attributes
205         for ($i = 0, $strlen = strlen($this->captcha_code); $i < $strlen; $i++)
206         {
207             // Allocate random color, size and rotation attributes to text
208             $text_color = imagecolorallocate($this->image, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
209             $angle = mt_rand(-40, 40);
210
211             // Make first char angle inward
212             if ($i === 0)
213             {
214                 $angle = -abs($angle);
215             }
216             // Make last char angle inward
217             if ($i === ($this->num_chars - 1))
218             {
219                 $angle = abs($angle);
220             }
221
222             // Scale the character size on image height
223             $font_size = mt_rand($this->height - 20, $this->height - 12);
224             $char_details = imageftbbox($font_size, $angle, $font, $this->captcha_code[$i], array());
225
226             // Calculate character starting coordinates
227             $iX = $this->spacing / 4 + $i * $this->spacing;
228             $char_height = $char_details[2] - $char_details[5];
229             $iY = $this->height / 2 + $char_height / 4;
230
231             // Write text character to image
232             imagefttext($this->image, $font_size, $angle, $iX, $iY, $text_color, $font, $this->captcha_code[$i], array());
233         }
234     }
235
236     /**
237      * Draws the alphasoup Captcha image:
238      * Requires GD with freetype and available truetype compatible font files.
239      *
240      * @param   none
241      * @return  void
242      */
243     protected function alphasoup_captcha()
244     {
245         $this->img_create();
246         $font = $this->font_path.$this->font_name;
247         $text_color = imagecolorallocate($this->image, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
248         $color_limit = mt_rand(96, 160);
249         $fill_color = imageColorAllocate($this->image, mt_rand($color_limit, 255), mt_rand($color_limit, 255), mt_rand($color_limit, 255));
250         imageFilledRectangle($this->image, 0, 0, $this->width, $this->height, $fill_color);
251         $font_width = imageFontWidth(10);
252         $chars = 'ABCDEFGHIJKLMNO';
253
254         for($loop = 0; $loop < 20; $loop++)
255         {
256             $text_color = imageColorAllocate($this->image, mt_rand($color_limit + 8, 255), mt_rand($color_limit + 8, 255), mt_rand($color_limit + 8, 255));
257             $char = substr($chars, mt_rand(0, 15), 1);
258             imageTTFtext($this->image, mt_rand(23, 27), mt_rand(160, 200), mt_rand(-10, $this->width + 10), mt_rand(-10, 60), $text_color, $font, $char);
259         }
260
261         $this->calculate_spacing();
262         // Draw each Captcha character with varying attributes
263         for ($i = 0, $strlen = strlen($this->captcha_code); $i < $strlen; $i++)
264         {
265             // Allocate random color, size and rotation attributes to text
266             $text_color = imagecolorallocate($this->image, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
267             $angle = mt_rand(-40, 40);
268
269             // Make first char angle inward
270             if ($i === 0)
271             {
272                 $angle = -abs($angle);
273             }
274             // Make last char angle inward
275             if ($i === ($this->num_chars - 1))
276             {
277                 $angle = abs($angle);
278             }
279
280             // Scale the character size on image height
281             $font_size = mt_rand($this->height - 20, $this->height - 12);
282             $char_details = imageftbbox($font_size, $angle, $font, $this->captcha_code[$i], array());
283
284             // Calculate character starting coordinates
285             $iX = $this->spacing / 4 + $i * $this->spacing;
286             $char_height = $char_details[2] - $char_details[5];
287             $iY = $this->height / 2 + $char_height / 4;
288
289             // Write text character to image
290             imagefttext($this->image, $font_size, $angle, $iX, $iY, $text_color, $font, $this->captcha_code[$i], array());
291         }
292
293     }
294
295     /**
296      * Draws the math riddle Captcha image.
297      * Requires GD with freetype and available truetype compatible font files.
298      *
299      * @return  void
300      */
301     protected function math_captcha()
302     {
303         $answer = Session::instance()->get('captcha_code');
304
305         // Convert to numeral
306         $numeral = $this->numerals[substr($answer, -1)];
307
308         // Subtract last digit from answer
309         $number = substr($answer, 0, 2).'0';
310
311         // $number plus $numeral equals $answer
312         $text = $number.' + '.$numeral.' = ';
313         $this->img_create();
314         $font = $this->font_path.$this->font_name;
315
316         // Scale the font size to image height
317         $font_size = $this->height / 3;
318         $text_details = imageftbbox($font_size, 0, $font, $text, array());
319         $iX = 5;
320         $iY = ($this->height / 2) + 5;
321
322         imagefttext($this->image, $font_size, 0, $iX, $iY, $this->color_white, $font, $text, array());
323     }
324
325     /**
326      * Calculates letter spacing for truetype font characters.
327      *
328      * @return  integer
329      */
330     protected function calculate_spacing()
331     {
332         return $this->spacing = (int) $this->width / $this->num_chars;
333     }
334
335     /**
336      * Fills the image with a colored gradient.
337      *
338      * @param   resource  gd image resource identifier
339      * @param   integer   start X position
340      * @param   integer   start Y position
341      * @param   integer   height of fill in pixels
342      * @param   integer   width of fill in pixels
343      * @param   resource  gd image color identifier for left of image
344      * @param   resource  gd image color identifier for right of image
345      * @return  void
346      */
347     protected function img_color_gradient($image, $x1, $y1, $height, $width, $left_color, $right_color)
348     {
349         $color0 = ($left_color[0] - $right_color[0]) / $width;
350         $color1 = ($left_color[1] - $right_color[1]) / $width;
351         $color2 = ($left_color[2] - $right_color[2]) / $width;
352
353         for ($i = 0; $i <= $width; $i++)
354         {
355             $red   = $left_color[0] - floor($i * $color0);
356             $green = $left_color[1] - floor($i * $color1);
357             $blue  = $left_color[2] - floor($i * $color2);
358             $col   = imagecolorallocate($this->image, $red, $green, $blue);
359
360             imageline($this->image, $x1 + $i, $y1, $x1 + $i, $y1 + $height, $col);
361         }
362     }
363
364 } // End Captcha Class
Note: See TracBrowser for help on using the browser.