| 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 | | } |
| | 149 | return $this->render(); |