1 <?php defined('SYSPATH') OR die('No direct access allowed.');
3 * Captcha driver class.
5 * $Id: Captcha.php 3769 2008-12-15 00:48:56Z zombor $
9 * @copyright (c) 2007-2008 Kohana Team
10 * @license http://kohanaphp.com/license.html
12 abstract class Captcha_Driver {
14 // The correct Captcha challenge answer
17 // Image resource identifier and type ("png", "gif" or "jpeg")
19 protected $image_type = 'png';
22 * Constructs a new challenge.
26 public function __construct()
28 // Generate a new challenge
29 $this->response = $this->generate_challenge();
31 // Store the correct Captcha response in a session
32 Event::add('system.post_controller', array($this, 'update_response_session'));
36 * Generate a new Captcha challenge.
38 * @return string the challenge answer
40 abstract public function generate_challenge();
43 * Output the Captcha challenge.
45 * @param boolean html output
46 * @return mixed the rendered Captcha (e.g. an image, riddle, etc.)
48 abstract public function render($html);
51 * Stores the response for the current Captcha challenge in a session so it is available
52 * on the next page load for Captcha::valid(). This method is called after controller
53 * execution (in the system.post_controller event) in order not to overwrite itself too soon.
57 public function update_response_session()
59 Session::instance()->set('captcha_response', sha1(strtoupper($this->response)));
63 * Validates a Captcha response from a user.
65 * @param string captcha response
68 public function valid($response)
70 return (sha1(strtoupper($response)) === Session::instance()->get('captcha_response'));
74 * Returns the image type.
76 * @param string filename
77 * @return string|FALSE image type ("png", "gif" or "jpeg")
79 public function image_type($filename)
81 switch (strtolower(substr(strrchr($filename, '.'), 1)))
91 // Return "jpeg" and not "jpg" because of the GD2 function names
100 * Creates an image resource with the dimensions specified in config.
101 * If a background image is supplied, the image dimensions are used.
103 * @throws Kohana_Exception if no GD2 support
104 * @param string path to the background image file
107 public function image_create($background = NULL)
109 // Check for GD2 support
110 if ( ! function_exists('imagegd2'))
111 throw new Kohana_Exception('captcha.requires_GD2');
113 // Create a new image (black)
114 $this->image = imagecreatetruecolor(Captcha::$config['width'], Captcha::$config['height']);
116 // Use a background image
117 if ( ! empty($background))
119 // Create the image using the right function for the filetype
120 $function = 'imagecreatefrom'.$this->image_type($background);
121 $this->background_image = $function($background);
123 // Resize the image if needed
124 if (imagesx($this->background_image) !== Captcha::$config['width']
125 OR imagesy($this->background_image) !== Captcha::$config['height'])
129 $this->image, $this->background_image, 0, 0, 0, 0,
130 Captcha::$config['width'], Captcha::$config['height'],
131 imagesx($this->background_image), imagesy($this->background_image)
136 imagedestroy($this->background_image);
141 * Fills the background with a gradient.
143 * @param resource gd image color identifier for start color
144 * @param resource gd image color identifier for end color
145 * @param string direction: 'horizontal' or 'vertical', 'random' by default
148 public function image_gradient($color1, $color2, $direction = NULL)
150 $directions = array('horizontal', 'vertical');
152 // Pick a random direction if needed
153 if ( ! in_array($direction, $directions))
155 $direction = $directions[array_rand($directions)];
158 if (mt_rand(0, 1) === 1)
166 // Extract RGB values
167 $color1 = imagecolorsforindex($this->image, $color1);
168 $color2 = imagecolorsforindex($this->image, $color2);
170 // Preparations for the gradient loop
171 $steps = ($direction === 'horizontal') ? Captcha::$config['width'] : Captcha::$config['height'];
173 $r1 = ($color1['red'] - $color2['red']) / $steps;
174 $g1 = ($color1['green'] - $color2['green']) / $steps;
175 $b1 = ($color1['blue'] - $color2['blue']) / $steps;
177 if ($direction === 'horizontal')
182 $y2 = Captcha::$config['height'];
188 $x2 = Captcha::$config['width'];
192 // Execute the gradient loop
193 for ($i = 0; $i <= $steps; $i++)
195 $r2 = $color1['red'] - floor($i * $r1);
196 $g2 = $color1['green'] - floor($i * $g1);
197 $b2 = $color1['blue'] - floor($i * $b1);
198 $color = imagecolorallocate($this->image, $r2, $g2, $b2);
200 imageline($this->image, $x1, $y1, $x2, $y2, $color);
205 * Returns the img html element or outputs the image to the browser.
207 * @param boolean html output
208 * @return mixed html string or void
210 public function image_render($html)
212 // Output html element
214 return '<img alt="Captcha" src="'.url::site('captcha/'.Captcha::$config['group']).'" width="'.Captcha::$config['width'].'" height="'.Captcha::$config['height'].'" />';
216 // Send the correct HTTP header
217 header('Content-Type: image/'.$this->image_type);
219 // Pick the correct output function
220 $function = 'image'.$this->image_type;
221 $function($this->image);
224 imagedestroy($this->image);
227 } // End Captcha Driver