PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/lhcaptcha/pear/Text/CAPTCHA/Driver/Image.php

http://hppg.googlecode.com/
PHP | 361 lines | 210 code | 23 blank | 128 comment | 43 complexity | e98288376e94ff88ba8475a83dcea5ce MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. *
  4. * Require Image_Text class for generating the text.
  5. *
  6. */
  7. require_once 'modules/lhcaptcha/pear/Text/CAPTCHA.php';
  8. require_once 'modules/lhcaptcha/pear/Image/Text.php';
  9. /**
  10. * Text_CAPTCHA_Driver_Image - Text_CAPTCHA driver graphical CAPTCHAs
  11. *
  12. * Class to create a graphical Turing test
  13. *
  14. *
  15. * @license PHP License, version 3.0
  16. * @author Christian Wenz <wenz@php.net>
  17. * @todo refine the obfuscation algorithm :-)
  18. * @todo learn how to use Image_Text better (or remove dependency)
  19. */
  20. class Text_CAPTCHA_Driver_Image extends Text_CAPTCHA
  21. {
  22. /**
  23. * Image object
  24. *
  25. * @access private
  26. * @var resource
  27. */
  28. var $_im;
  29. /**
  30. * Image_Text object
  31. *
  32. * @access private
  33. * @var resource
  34. */
  35. var $_imt;
  36. /**
  37. * Width of CAPTCHA
  38. *
  39. * @access private
  40. * @var int
  41. */
  42. var $_width;
  43. /**
  44. * Height of CAPTCHA
  45. *
  46. * @access private
  47. * @var int
  48. */
  49. var $_height;
  50. /**
  51. * CAPTCHA output format
  52. *
  53. * @access private
  54. * @var string
  55. */
  56. var $_output;
  57. /**
  58. * Further options (here: for Image_Text)
  59. *
  60. * @access private
  61. * @var array
  62. */
  63. var $_imageOptions = array(
  64. 'font_size' => 24,
  65. 'font_path' => './',
  66. 'font_file' => 'COUR.TTF',
  67. 'text_color' => '#000000',
  68. 'lines_color' => '#CACACA',
  69. 'background_color' => '#555555');
  70. /**
  71. * Whether the immage resource has been created
  72. *
  73. * @access private
  74. * @var boolean
  75. */
  76. var $_created = false;
  77. /**
  78. * Last error
  79. *
  80. * @access protected
  81. * @var PEAR_Error
  82. */
  83. var $_error = null;
  84. /**
  85. * init function
  86. *
  87. * Initializes the new Text_CAPTCHA_Driver_Image object and creates a GD image
  88. *
  89. * @param array $options CAPTCHA options
  90. * @access public
  91. * @return mixed true upon success, PEAR error otherwise
  92. */
  93. function init($options = array())
  94. {
  95. if (!is_array($options)) {
  96. // Compatibility mode ... in future versions, these two
  97. // lines of code will be used:
  98. // $this->_error = PEAR::raiseError('You need to provide a set of CAPTCHA options!');
  99. // return $this->_error;
  100. $o = array();
  101. $args = func_get_args();
  102. if (isset($args[0])) {
  103. $o['width'] = $args[0];
  104. }
  105. if (isset($args[1])) {
  106. $o['height'] = $args[1];
  107. }
  108. if (isset($args[2]) && $args[2] != null) {
  109. $o['phrase'] = $args[2];
  110. }
  111. if (isset($args[3]) && is_array($args[3])) {
  112. $o['imageOptions'] = $args[3];
  113. }
  114. $options = $o;
  115. }
  116. if (is_array($options)) {
  117. if (isset($options['width']) && is_int($options['width'])) {
  118. $this->_width = $options['width'];
  119. } else {
  120. $this->_width = 200;
  121. }
  122. if (isset($options['height']) && is_int($options['height'])) {
  123. $this->_height = $options['height'];
  124. } else {
  125. $this->_height = 80;
  126. }
  127. if (!isset($options['phrase']) || empty($options['phrase'])) {
  128. $this->_createPhrase();
  129. } else {
  130. $this->_phrase = $options['phrase'];
  131. }
  132. if (!isset($options['output']) || empty($options['output'])) {
  133. $this->_output = 'resource';
  134. } else {
  135. $this->_output = $options['output'];
  136. }
  137. if (isset($options['imageOptions']) && is_array($options['imageOptions']) && count($options['imageOptions']) > 0) {
  138. $this->_imageOptions = array_merge($this->_imageOptions, $options['imageOptions']);
  139. }
  140. return true;
  141. }
  142. }
  143. /**
  144. * Create random CAPTCHA phrase, Image edition (with size check)
  145. *
  146. * This method creates a random phrase, maximum 8 characters or width / 25, whatever is smaller
  147. *
  148. * @access private
  149. */
  150. function _createPhrase()
  151. {
  152. $len = intval(min(8, $this->_width / 25));
  153. $this->_phrase = Text_Password::create($len);
  154. $this->_created = false;
  155. }
  156. /**
  157. * Create CAPTCHA image
  158. *
  159. * This method creates a CAPTCHA image
  160. *
  161. * @access private
  162. * @return void PEAR_Error on error
  163. */
  164. function _createCAPTCHA()
  165. {
  166. if ($this->_error) {
  167. return $this->_error;
  168. }
  169. if ($this->_created) {
  170. return;
  171. }
  172. $options['canvas'] = array(
  173. 'width' => $this->_width,
  174. 'height' => $this->_height
  175. );
  176. $options['width'] = $this->_width - 20;
  177. $options['height'] = $this->_height - 20;
  178. $options['cx'] = ceil(($this->_width) / 2 + 10);
  179. $options['cy'] = ceil(($this->_height) / 2 + 10);
  180. $options['angle'] = rand(0, 30) - 15;
  181. $options['font_size'] = $this->_imageOptions['font_size'];
  182. $options['font_path'] = $this->_imageOptions['font_path'];
  183. $options['font_file'] = $this->_imageOptions['font_file'];
  184. $options['color'] = array($this->_imageOptions['text_color']);
  185. $options['background_color'] = $this->_imageOptions['background_color'];
  186. $options['max_lines'] = 1;
  187. $options['mode'] = 'auto';
  188. $this->_imt = new Image_Text(
  189. $this->_phrase,
  190. $options
  191. );
  192. if (PEAR::isError($e = $this->_imt->init())) {
  193. $this->_error = PEAR::raiseError(
  194. sprintf('Error initializing Image_Text (%s)',
  195. $e->getMessage()));
  196. return $this->_error;
  197. } else {
  198. $this->_created = true;
  199. }
  200. $this->_imt->measurize();
  201. $this->_imt->render();
  202. $this->_im =& $this->_imt->getImg();
  203. $colors = $this->_imt->_convertString2RGB($this->_imageOptions['lines_color']);
  204. $lines_color = imagecolorallocate($this->_im, $colors['r'], $colors['g'], $colors['b']);
  205. //some obfuscation
  206. for ($i = 0; $i < 3; $i++) {
  207. $x1 = rand(0, $this->_width - 1);
  208. $y1 = rand(0, round($this->_height / 10, 0));
  209. $x2 = rand(0, round($this->_width / 10, 0));
  210. $y2 = rand(0, $this->_height - 1);
  211. imageline($this->_im, $x1, $y1, $x2, $y2, $lines_color);
  212. $x1 = rand(0, $this->_width - 1);
  213. $y1 = $this->_height - rand(1, round($this->_height / 10, 0));
  214. $x2 = $this->_width - rand(1, round($this->_width / 10, 0));
  215. $y2 = rand(0, $this->_height - 1);
  216. imageline($this->_im, $x1, $y1, $x2, $y2, $lines_color);
  217. $cx = rand(0, $this->_width - 50) + 25;
  218. $cy = rand(0, $this->_height - 50) + 25;
  219. $w = rand(1, 24);
  220. imagearc($this->_im, $cx, $cy, $w, $w, 0, 360, $lines_color);
  221. }
  222. }
  223. /**
  224. * Return CAPTCHA as image resource
  225. *
  226. * This method returns the CAPTCHA depending on the output format
  227. *
  228. * @access public
  229. * @return mixed image resource or PEAR error
  230. */
  231. function getCAPTCHA()
  232. {
  233. $retval = $this->_createCAPTCHA();
  234. if (PEAR::isError($retval)) {
  235. return PEAR::raiseError($retval->getMessage());
  236. }
  237. if ($this->_output == 'gif' && !function_exists('imagegif')) {
  238. $this->_output = 'png';
  239. }
  240. switch ($this->_output) {
  241. case 'png':
  242. return $this->getCAPTCHAAsPNG();
  243. break;
  244. case 'jpg':
  245. case 'jpeg':
  246. return $this->getCAPTCHAAsJPEG();
  247. break;
  248. case 'gif':
  249. return $this->getCAPTCHAAsGIF();
  250. break;
  251. case 'resource':
  252. default:
  253. return $this->_im;
  254. }
  255. }
  256. /**
  257. * Return CAPTCHA as PNG
  258. *
  259. * This method returns the CAPTCHA as PNG
  260. *
  261. * @access public
  262. * @return mixed image contents or PEAR error
  263. */
  264. function getCAPTCHAAsPNG()
  265. {
  266. $retval = $this->_createCAPTCHA();
  267. if (PEAR::isError($retval)) {
  268. return PEAR::raiseError($retval->getMessage());
  269. }
  270. if (is_resource($this->_im)) {
  271. ob_start();
  272. imagepng($this->_im);
  273. $data = ob_get_contents();
  274. ob_end_clean();
  275. return $data;
  276. } else {
  277. $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
  278. return $this->_error;
  279. }
  280. }
  281. /**
  282. * Return CAPTCHA as JPEG
  283. *
  284. * This method returns the CAPTCHA as JPEG
  285. *
  286. * @access public
  287. * @return mixed image contents or PEAR error
  288. */
  289. function getCAPTCHAAsJPEG()
  290. {
  291. $retval = $this->_createCAPTCHA();
  292. if (PEAR::isError($retval)) {
  293. return PEAR::raiseError($retval->getMessage());
  294. }
  295. if (is_resource($this->_im)) {
  296. ob_start();
  297. imagejpeg($this->_im);
  298. $data = ob_get_contents();
  299. ob_end_clean();
  300. return $data;
  301. } else {
  302. $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
  303. return $this->_error;
  304. }
  305. }
  306. /**
  307. * Return CAPTCHA as GIF
  308. *
  309. * This method returns the CAPTCHA as GIF
  310. *
  311. * @access public
  312. * @return mixed image contents or PEAR error
  313. */
  314. function getCAPTCHAAsGIF()
  315. {
  316. $retval = $this->_createCAPTCHA();
  317. if (PEAR::isError($retval)) {
  318. return PEAR::raiseError($retval->getMessage());
  319. }
  320. if (is_resource($this->_im)) {
  321. ob_start();
  322. imagegif($this->_im);
  323. $data = ob_get_contents();
  324. ob_end_clean();
  325. return $data;
  326. } else {
  327. $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
  328. return $this->_error;
  329. }
  330. }
  331. /**
  332. * __wakeup method (PHP 5 only)
  333. */
  334. function __wakeup()
  335. {
  336. $this->_created = false;
  337. }
  338. }