PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Captcha.php

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