PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Lampcms/Captcha/Captcha.php

http://github.com/snytkine/LampCMS
PHP | 851 lines | 351 code | 133 blank | 367 comment | 64 complexity | 780a8e5f14edeae57b417efff29d6b19 MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. /**
  3. * PHP-Class hn_captcha_X1 Version 1.2.1, released 30-Apr-2009
  4. *
  5. * is an extension for PHP-Class hn_captcha, Version for PHP 5 !
  6. *
  7. * It adds a garbage-collector. (Useful, if you cannot use cronjobs.)
  8. *
  9. *
  10. * Author: Horst Nogajski, coding@nogajski.de
  11. *
  12. * $Id: hn_captcha.class.x1.php5,v 1.4.2.2 2009/04/30 14:30:06 horst Exp $
  13. *
  14. * Download: http://hn273.users.phpclasses.org/browse/package/1569.html
  15. *
  16. * License: GNU LGPL (http://www.opensource.org/licenses/lgpl-license.html)
  17. *
  18. * This library is free software; you can redistribute it and/or
  19. * modify it under the terms of the GNU Lesser General Public
  20. * License as published by the Free Software Foundation; either
  21. * version 2.1 of the License, or (at your option) any later version.
  22. *
  23. * This library is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  26. * Lesser General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU Lesser General Public
  29. * License along with this library; if not, write to the Free Software
  30. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  31. *
  32. *
  33. * This class generates a picture to use in forms that perform CAPTCHA test
  34. * (Completely Automated Public Turing to tell Computers from Humans Apart).
  35. * After the test form is submitted a key entered by the user in a text field
  36. * is compared by the class to determine whether it matches the text in the picture.
  37. *
  38. * The class is a fork of the original released at www.phpclasses.org
  39. * by Julien Pachet with the name ocr_captcha.
  40. *
  41. * The following enhancements were added:
  42. *
  43. * - Support to make it work with GD library before version 2
  44. * - Hacking prevention
  45. * - Optional use of Web safe colors
  46. * - Limit the number of users attempts
  47. * - Display an optional refresh link to generate a new picture with a different key
  48. * without counting to the user attempts limit verification
  49. * - Support the use of multiple random TrueType fonts
  50. * - Control the output image by only three parameters: number of text characters
  51. * and minimum and maximum size preserving the size proportion
  52. * - Preserve all request parameters passed to the page via the GET method,
  53. * so the CAPTCHA test can be added to existing scripts with minimal changes
  54. * - Added a debug option for testing the current configuration
  55. */
  56. namespace Lampcms\Captcha;
  57. use \Lampcms\DevException;
  58. /**
  59. * All the configuration settings are passed to the class in an array when the object instance is initialized.
  60. *
  61. * The class only needs two function calls to be used: display_form() and validate_submit().
  62. *
  63. *
  64. * Class that generate a captcha-image with text and a form to fill in this text
  65. *
  66. * @author Horst Nogajski, (mail: horst@nogajski.de)
  67. * @version 1.3
  68. *
  69. */
  70. class Captcha
  71. {
  72. ////////////////////////////////
  73. //
  74. // PUBLIC PARAMS
  75. //
  76. /**
  77. * Absolute path to a Tempfolder (with trailing slash!).
  78. * This must be writeable for PHP and also accessible via HTTP,
  79. * because the image will be stored there.
  80. *
  81. * @var string
  82. *
  83. * @access public
  84. *
  85. */
  86. protected $tempfolder;
  87. /**
  88. * Absolute path to folder with TrueTypeFonts (with trailing slash!).
  89. * This must be readable by PHP.
  90. *
  91. * @protected string
  92. *
  93. **/
  94. protected $TTF_folder;
  95. /**
  96. * How many chars the generated text should have
  97. *
  98. * @type integer
  99. * @access public
  100. *
  101. **/
  102. protected $chars = 5;
  103. /**
  104. * The minimum size a Char should have
  105. *
  106. * @type integer
  107. * @access public
  108. *
  109. **/
  110. protected $minsize = 20;
  111. /**
  112. * The maximum size a Char can have
  113. *
  114. * @type integer
  115. * @access public
  116. *
  117. **/
  118. protected $maxsize = 30;
  119. /**
  120. * The maximum degrees a Char should be rotated. Set it to 30 means a random rotation between -30 and 30.
  121. *
  122. * @type integer
  123. * @access public
  124. *
  125. **/
  126. protected $maxrotation = 25;
  127. /**
  128. * Background noise On/Off (if is Off, a grid will be created)
  129. *
  130. * @type boolean
  131. * @access public
  132. *
  133. **/
  134. protected $noise = true;
  135. /**
  136. * This will only use the 216 websafe color pallette for the image.
  137. *
  138. * @type boolean
  139. * @access public
  140. *
  141. **/
  142. protected $websafecolors = false;
  143. /**
  144. * Switches language, available are 'en' and 'de'. You can easily add more. Look in CONSTRUCTOR.
  145. *
  146. * @type string
  147. * @access public
  148. *
  149. **/
  150. protected $lang = "en";
  151. /**
  152. * If a user has reached this number of try's without success, he will moved to the $badguys_url
  153. *
  154. * @type integer
  155. * @access public
  156. *
  157. **/
  158. protected $maxtry = 3;
  159. /**
  160. * Gives the user the possibility to generate a new captcha-image.
  161. *
  162. * @type boolean
  163. * @access public
  164. *
  165. **/
  166. protected $refreshlink = true;
  167. /**
  168. * If a user has reached his maximum try's, he will located to this url.
  169. *
  170. * @type boolean
  171. * @access public
  172. *
  173. **/
  174. protected $badguys_url = "/";
  175. /**
  176. * Number between 1 and 32
  177. *
  178. * Defines the position of 'current try number' in (32-char-length)-string generated by function get_try()
  179. *
  180. * @type integer
  181. * @access public
  182. *
  183. **/
  184. protected $secretposition = 15;
  185. /**
  186. * The string is used to generate the md5-key.
  187. *
  188. * @type string
  189. * @access public
  190. *
  191. **/
  192. protected $secretstring = "A very interesting string like 8 char password!";
  193. /**
  194. * Outputs configuration values for testing
  195. *
  196. * @type boolean
  197. * @access public
  198. *
  199. **/
  200. protected $debug = false;
  201. /** @access public **/
  202. public $msg1;
  203. /** @access public **/
  204. public $msg2;
  205. ////////////////////////////////
  206. //
  207. // PRIVATE PARAMS
  208. //
  209. /** @private **/
  210. private $lx; // width of picture
  211. /** @private **/
  212. private $ly; // height of picture
  213. /** @private **/
  214. private $jpegquality = 80; // image quality
  215. /** @private **/
  216. private $noisefactor = 9; // this will multiplyed with number of chars
  217. /** @private **/
  218. private $nb_noise; // number of background-noise-characters
  219. /** @private **/
  220. private $TTF_file = 'font.ttf'; // holds the current selected TrueTypeFont
  221. /** @private **/
  222. private $buttontext;
  223. /** @private **/
  224. private $refreshbuttontext;
  225. /** @private **/
  226. private $public_K;
  227. /** @private **/
  228. private $private_K;
  229. /** @private **/
  230. private $key; // md5-key
  231. /** @private **/
  232. private $public_key; // public key
  233. /** @private **/
  234. private $filename; // filename of captcha picture
  235. /** @private **/
  236. private $gd_version; // holds the Version Number of GD-Library
  237. /** @private **/
  238. // private $QUERY_STRING; // keeps the ($_GET) Querystring of the original Request
  239. /** @private **/
  240. private $current_try = 0;
  241. /** @private **/
  242. private $r;
  243. /** @private **/
  244. private $g;
  245. /** @private **/
  246. private $b;
  247. /**
  248. * Factory method
  249. * Will return Dummy object
  250. * in case user does not have required
  251. * GD and imagettftext function
  252. *
  253. * Otherwise will return object of this class
  254. *
  255. * @param \Lampcms\Config\Ini object
  256. *
  257. * @return \Lampcms\Captcha\Captcha|\Lampcms\Captcha\CaptchaStub
  258. */
  259. public static function factory(\Lampcms\Config\Ini $Ini)
  260. {
  261. d('cp captcha factory');
  262. $aConfig = $Ini->getSection('CAPTCHA');
  263. if (!empty($aConfig['disabled'])) {
  264. d('Captcha disabled by administrator. Using Captcha Stub instead');
  265. return new CaptchaStub();
  266. }
  267. try {
  268. self::checkGD();
  269. return new self($Ini, $aConfig);
  270. } catch ( DevException $e ) {
  271. e('Unable to use Captcha because of this error: ' . $e->getMessage());
  272. return new CaptchaStub();
  273. }
  274. }
  275. /**
  276. * Extracts the config array and generate needed params.
  277. *
  278. * @param \Lampcms\Config\Ini $Ini
  279. * @param array $config
  280. * @param bool $secure
  281. * @param bool $debug
  282. *
  283. * @throws \Lampcms\Exception
  284. * @throws \Lampcms\DevException
  285. */
  286. public function __construct(\Lampcms\Config\Ini $Ini, array $config = array(), $secure = true, $debug = false)
  287. {
  288. $this->Ini = $Ini;
  289. $aConfig = (!empty($config)) ? $config : $Ini->getSection('CAPTCHA');
  290. d('Captcha config: ' . \json_encode($aConfig));
  291. d("Captcha-Debug: The available GD-Library has major version " . $this->gd_version);
  292. $this->tempfolder = LAMPCMS_DATA_DIR . 'img' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
  293. $this->TTF_file = LAMPCMS_CONFIG_DIR. DIRECTORY_SEPARATOR .'fonts' . DIRECTORY_SEPARATOR . 'font.ttf';
  294. d('$this->tempfolder: ' . $this->tempfolder . ' $this->TTF_folder: ' . $this->TTF_folder);
  295. // Hack prevention
  296. if (
  297. (isset($_GET['maxtry']) || isset($_POST['maxtry']) || isset($_COOKIE['maxtry']))
  298. ||
  299. (isset($_GET['debug']) || isset($_POST['debug']) || isset($_COOKIE['debug']))
  300. ||
  301. (isset($_GET['captcharefresh']) || isset($_COOKIE['captcharefresh']))
  302. ||
  303. (isset($_POST['captcharefresh']) && isset($_POST['private_key']))
  304. ) {
  305. d("Captcha-Debug: bad guy detected!");
  306. if (isset($this->badguys_url) && !headers_sent()) {
  307. header('Location: ' . $this->badguys_url);
  308. } else {
  309. throw new \Lampcms\Exception('Sorry but something is not right with this captcha image');
  310. }
  311. }
  312. // extracts config array
  313. if (!empty($aConfig)) {
  314. d("Captcha-Debug: Extracts Config-Array in secure-mode!");
  315. $valid = get_object_vars($this);
  316. // d('valid vars: '.print_r($valid, 1));
  317. foreach ($aConfig as $k => $v) {
  318. if (array_key_exists($k, $valid)) {
  319. $this->$k = $v; // key/val from $config become instance variables here
  320. }
  321. }
  322. }
  323. // check vars for maxtry, secretposition and min-max-size
  324. $this->maxtry = ($this->maxtry > 9 || $this->maxtry < 1) ? 3 : $this->maxtry;
  325. $this->secretposition = ($this->secretposition > 32 || $this->secretposition < 1) ? $this->maxtry : $this->secretposition;
  326. if ($this->minsize > $this->maxsize) {
  327. $temp = $this->minsize;
  328. $this->minsize = $this->maxsize;
  329. $this->maxsize = $temp;
  330. e("What do you think I mean with min and max? Switch minsize with maxsize.");
  331. }
  332. d("Set current TrueType-File: (" . $this->TTF_file . ")");
  333. // get number of noise-chars for background if is enabled
  334. $this->nb_noise = $this->noise ? ($this->chars * $this->noisefactor) : 0;
  335. d("Set number of noise characters to: (" . $this->nb_noise . ")");
  336. // set dimension of image
  337. $this->lx = ($this->chars + 1) * (int)(($this->maxsize + $this->minsize) / 1.5);
  338. $this->ly = (int)(2.4 * $this->maxsize);
  339. d("Set image dimension to: (" . $this->lx . " x " . $this->ly . ")");
  340. d("Set messages to language: (" . $this->lang . ")");
  341. // check Postvars
  342. if (isset($_POST['public_key'])) {
  343. $this->public_K = substr(strip_tags($_POST['public_key']), 0, $this->chars);
  344. }
  345. /**
  346. * Replace Z with 0 for submitted captcha text
  347. * because we replace 0 with Z when generated image
  348. * So now we must make sure to replace it back to 0
  349. * str_replace('Z', '0',
  350. */
  351. if (isset($_POST['private_key'])) {
  352. $this->private_K = substr(strip_tags($_POST['private_key']), 0, $this->chars);
  353. }
  354. $this->current_try = isset($_POST['hncaptcha']) ? $this->get_try() : 0;
  355. if (!isset($_POST['captcharefresh'])) {
  356. $this->current_try++;
  357. }
  358. d("Check POST-vars, current try is: (" . $this->current_try . ")");
  359. // generate Keys
  360. $this->key = md5($this->secretstring);
  361. $this->public_key = substr(md5(uniqid(rand(), true)), 0, $this->chars);
  362. d('public key is: ' . $this->public_key);
  363. } // end constructor
  364. /**
  365. * validates POST-vars and return result
  366. *
  367. * @return int 0 = first call | 1 = valid submit | 2 = not valid | 3 = not valid and has reached maximum tries
  368. */
  369. public function validate_submit()
  370. {
  371. $chk = $this->check_captcha($this->public_K, $this->private_K);
  372. if ($chk) {
  373. d("Captcha-Debug: Captcha is valid, validating submitted form returns: (1)");
  374. return 1;
  375. } else {
  376. if ($this->current_try > $this->maxtry) {
  377. d("Captcha-Debug: Validating submitted form returns: (3)");
  378. return 3;
  379. } elseif ($this->current_try > 0) {
  380. d("Captcha-Debug: Validating submitted form returns: (2)");
  381. return 2;
  382. } else {
  383. d("Captcha-Debug: Validating submitted form returns: (0)");
  384. return 0;
  385. }
  386. }
  387. }
  388. public function display_captcha()
  389. {
  390. $this->make_captcha();
  391. $is = getimagesize($this->get_filename());
  392. return "\n" . '<img class="captchapict" src="' . $this->get_filename_url() . '" ' . $is[3] . ' alt="@@This is a captcha-picture. It is used to prevent mass-access by robots. see www.captcha.net@@" title="">' . "\n";
  393. }
  394. /**
  395. * must be public to work on our project
  396. */
  397. public function make_captcha()
  398. {
  399. $private_key = $this->generate_private();
  400. d("Captcha-Debug: Generate private key: ($private_key)");
  401. // create Image and set the appropriate function depending on GD-Version & websafecolor-value
  402. if ($this->gd_version >= 2 && !$this->websafecolors) {
  403. $func1 = '\\imagecreatetruecolor';
  404. $func2 = '\\imagecolorallocate';
  405. } else {
  406. $func1 = '\\imagecreate';
  407. $func2 = '\\imagecolorclosest';
  408. }
  409. $image = $func1($this->lx, $this->ly);
  410. d("Generate ImageStream with: ($func1)");
  411. d("For colordefinitions we use: ($func2)");
  412. d('$image is: ' . gettype($image));
  413. // Set Backgroundcolor
  414. $this->random_color(224, 255);
  415. $back = @\imagecolorallocate($image, $this->r, $this->g, $this->b);
  416. \imagefilledrectangle($image, 0, 0, $this->lx, $this->ly, $back);
  417. d("Captcha-Debug: We allocate one color for Background: (" . $this->r . "-" . $this->g . "-" . $this->b . ")");
  418. // allocates the 216 websafe color palette to the image
  419. if ($this->gd_version < 2 || $this->websafecolors) {
  420. $this->makeWebsafeColors($image);
  421. }
  422. // fill with noise or grid
  423. if ($this->nb_noise > 0) {
  424. // random characters in background with random position, angle, color
  425. d("Captcha-Debug: Fill background with noise: (" . $this->nb_noise . ")");
  426. for ($i = 0; $i < $this->nb_noise; $i++) {
  427. //d('Captcha-Debug');
  428. $size = (int)(\mt_rand((int)($this->minsize / 2.3), (int)($this->maxsize / 1.7)));
  429. $angle = (int)(\mt_rand(0, 360));
  430. $x = (int)(\mt_rand(0, $this->lx));
  431. $y = (int)(\mt_rand(0, (int)($this->ly - ($size / 5))));
  432. $this->random_color(160, 224);
  433. $color = $func2($image, $this->r, $this->g, $this->b);
  434. $text = chr((int)(\mt_rand(45, 250)));
  435. if (false === \imagettftext($image, $size, $angle, $x, $y, $color, $this->TTF_file, $text)) {
  436. throw new DevException('Your php does not support imagettftext operation OR your fonts file did not upload correctly (hint: did you upload them in text mode instead of binary?). You should disable captcha support in !config.ini');
  437. }
  438. //d('Captcha-Debug');
  439. }
  440. } else {
  441. // generate grid
  442. d("Captcha-Debug: Fill background with x-gridlines: (" . (int)($this->lx / (int)($this->minsize / 1.5)) . ")");
  443. for ($i = 0; $i < $this->lx; $i += (int)($this->minsize / 1.5)) {
  444. $this->random_color(160, 224);
  445. $color = $func2($image, $this->r, $this->g, $this->b);
  446. @imageline($image, $i, 0, $i, $this->ly, $color);
  447. }
  448. d("Captcha-Debug: Fill background with y-gridlines: (" . (int)($this->ly / (int)(($this->minsize / 1.8))) . ")");
  449. for ($i = 0; $i < $this->ly; $i += (int)($this->minsize / 1.8)) {
  450. $this->random_color(160, 224);
  451. $color = $func2($image, $this->r, $this->g, $this->b);
  452. @imageline($image, 0, $i, $this->lx, $i, $color);
  453. }
  454. }
  455. // generate Text
  456. d("Captcha-Debug: Fill foreground with chars and shadows: (" . $this->chars . ")");
  457. for ($i = 0, $x = (int)(\mt_rand($this->minsize, $this->maxsize)); $i < $this->chars; $i++) {
  458. //d('Captcha-Debug');
  459. $text = \strtoupper(\substr($private_key, $i, 1));
  460. //d('Captcha-Debug: $text: '.$text);
  461. $angle = (int)(\mt_rand(($this->maxrotation * -1), $this->maxrotation));
  462. $size = (int)(\mt_rand($this->minsize, $this->maxsize));
  463. $y = (int)(\mt_rand((int)($size * 1.5), (int)($this->ly - ($size / 7))));
  464. $this->random_color(0, 127);
  465. //d('Captcha-Debug');
  466. $color = $func2($image, $this->r, $this->g, $this->b);
  467. //d('Captcha-Debug');
  468. $this->random_color(0, 127);
  469. $shadow = $func2($image, $this->r + 127, $this->g + 127, $this->b + 127);
  470. //d('Captcha-Debug');
  471. @\imagettftext($image, $size, $angle, $x + (int)($size / 15), $y, $shadow, $this->TTF_file, $text);
  472. @\imagettftext($image, $size, $angle, $x, $y - (int)($size / 15), $color, $this->TTF_file, $text);
  473. $x += (int)($size + ($this->minsize / 5));
  474. //d('Captcha-Debug');
  475. }
  476. d('$image: ' . \gettype($image) . ' image file: ' . $this->get_filename() . ' $this->jpegquality: ' . $this->jpegquality);
  477. if (true !== \imagejpeg($image, $this->get_filename(), $this->jpegquality)) {
  478. e('error writing captcha image. Make sure your www/w directory and ALL subdirectory have writable permission');
  479. throw new DevException('Unable to save captcha-image to ' . $this->get_filename().' Make sure your www/w directory and ALL subdirectory have writable permission');
  480. }
  481. if (!file_exists($this->get_filename())) {
  482. e('Unable to save captcha file to ' . $this->get_filename().' Make sure your www/w directory and ALL subdirectory have writable permission');
  483. throw new DevException('Unable to save captcha-image to ' . $this->get_filename().' Make sure your www/w directory and ALL subdirectory have writable permission');
  484. }
  485. //d('Captcha-Debug');
  486. if (true !== \imagedestroy($image)) {
  487. e("Captcha-Debug: Destroy GD Image Resource failed.");
  488. }
  489. //d('Captcha-Debug');
  490. }
  491. /**
  492. *
  493. * Enter description here ...
  494. *
  495. * @param unknown_type $image
  496. */
  497. protected function makeWebsafeColors(&$image)
  498. {
  499. //$a = array();
  500. for ($r = 0; $r <= 255; $r += 51) {
  501. for ($g = 0; $g <= 255; $g += 51) {
  502. for ($b = 0; $b <= 255; $b += 51) {
  503. $color = imagecolorallocate($image, $r, $g, $b);
  504. }
  505. }
  506. }
  507. d("Captcha-Debug: Allocate 216 websafe colors to image: (" . imagecolorstotal($image) . ")");
  508. //return $a;
  509. }
  510. /**
  511. *
  512. * Enter description here ...
  513. *
  514. * @param int $min
  515. * @param int $max
  516. */
  517. protected function random_color($min, $max)
  518. {
  519. $this->r = (int)(mt_rand($min, $max));
  520. $this->g = (int)(mt_rand($min, $max));
  521. $this->b = (int)(mt_rand($min, $max));
  522. }
  523. /**
  524. * Check captcha
  525. *
  526. * @param string $public public key
  527. * @param string $private private key
  528. *
  529. * @return bool
  530. */
  531. protected function check_captcha($public, $private)
  532. {
  533. $res = false;
  534. /**
  535. * when check, destroy picture on disk
  536. */
  537. if (file_exists($this->get_filename($public))) {
  538. $ret = @unlink($this->get_filename($public)) ? true : false;
  539. if ($this->debug) {
  540. d("Captcha-Debug: Delete image (" . $this->get_filename($public) . ") returns: ($ret)");
  541. }
  542. $res = (strtolower($private) == strtolower($this->generate_private($public)));
  543. d("Captcha-Debug: Comparing public with private key returns: ($res)");
  544. d('PRIV: ' . strtolower($private) . " ? Generated-PRIVATE (from public=$public) : " . strtolower($this->generate_private($public)));
  545. } else {
  546. e('Captcha-Debug: file does not exist ' . $this->get_filename($public));
  547. }
  548. return $res;
  549. }
  550. /**
  551. * must be public for Lampcms project
  552. *
  553. * @param string $public
  554. *
  555. * @return string
  556. */
  557. public function get_filename($public = "")
  558. {
  559. if ($public == "") {
  560. $public = $this->public_key;
  561. }
  562. return $this->tempfolder . $public . ".jpg";
  563. }
  564. /**
  565. *
  566. *
  567. * @param string $public
  568. *
  569. * @return string
  570. */
  571. public function get_filename_url($public = "")
  572. {
  573. if ($public == "") {
  574. $public = $this->public_key;
  575. }
  576. return '{_DIR_}/w/img/tmp/' . $public . ".jpg";
  577. }
  578. /**
  579. *
  580. * @return array with 3 elements: src = the web path (relative),
  581. * 'w' = width, 'h' = height
  582. */
  583. public function getCaptchaImage()
  584. {
  585. $this->make_captcha();
  586. $is = getimagesize($this->tempfolder . $this->public_key . '.jpg');
  587. return array('src' => '{_DIR_}/w/img/tmp/' . $this->public_key . '.jpg',
  588. 'w' => $is[0],
  589. 'h' => $is[1]);
  590. }
  591. /**
  592. * Must be public to work on Lampcms project
  593. *
  594. * @param bool $in
  595. *
  596. * @return int|string
  597. */
  598. public function get_try($in = true)
  599. {
  600. $s = array();
  601. for ($i = 1; $i <= $this->maxtry; $i++) {
  602. $s[$i] = $i;
  603. }
  604. if ($in) {
  605. return (int)substr(\strip_tags($_POST['hncaptcha']), ($this->secretposition - 1), 1);
  606. } else {
  607. $a = "";
  608. $b = "";
  609. for ($i = 1; $i < $this->secretposition; $i++) {
  610. $a .= $s[(int)(\mt_rand(1, $this->maxtry))];
  611. }
  612. for ($i = 0; $i < (32 - $this->secretposition); $i++) {
  613. $b .= $s[(int)(\mt_rand(1, $this->maxtry))];
  614. }
  615. return $a . $this->current_try . $b;
  616. }
  617. }
  618. /**
  619. * Get version of php GD extension
  620. *
  621. * @return version of GD
  622. *
  623. * @throws \Lampcms\DevException if GD not available
  624. * or not compiled with imatettftext support
  625. * or does not have JPEG support
  626. */
  627. public static function checkGD()
  628. {
  629. if (!extension_loaded('gd')) {
  630. throw new DevException('GD module not loaded. Cannot use Captcha class without GD library. Check your php info');
  631. }
  632. if (!function_exists('imagettftext')) {
  633. throw new DevException('Your php installation does not have the "imagettftext" function. Captcha cannot be used without this function. ');
  634. }
  635. $gd_info = gd_info();
  636. if (empty($gd_info['JPG Support']) && empty($gd_info['JPEG Support'])) {
  637. throw new DevException('Your php GD version does not have support for JPG image. Captcha cannot be used without JPG support in GD');
  638. }
  639. if (empty($gd_info['GD Version'])) {
  640. throw new DevException('Unknown version of GD. Unable to use Captcha');
  641. }
  642. $gdv = $gd_info['GD Version'];
  643. d('$gdv: ' . $gdv);
  644. $Version = \preg_replace('/[[:alpha:][:space:]()]+/', '', $gdv);
  645. d('Version: ' . $Version);
  646. if (version_compare($Version, 2.0) < 0) {
  647. throw new DevException('GD version must be newer than 2.0. Your installed version is: ' . $Version . ' Captcha will not be used');
  648. }
  649. return $Version;
  650. }
  651. /**
  652. *
  653. * The private key will be used
  654. * for the actual image of captcha
  655. *
  656. * @param string $public
  657. *
  658. * @return mixed|string
  659. */
  660. protected function generate_private($public = "")
  661. {
  662. if ($public == "") {
  663. $public = $this->public_key;
  664. }
  665. d("public key WHICH USED for generate private key $public");
  666. $key = \substr(md5($this->key . $public), 16 - $this->chars / 2, $this->chars);
  667. /**
  668. * 0 will be replaced with Z
  669. * because 0 renders badly in our font
  670. *
  671. */
  672. $key = \str_replace('0', 'Z', $key);
  673. return $key;
  674. }
  675. /**
  676. * getter method to get public_key
  677. * which is a private var
  678. *
  679. * @return string value of public_key
  680. */
  681. public function getPublicKey()
  682. {
  683. return $this->public_key;
  684. }
  685. /**
  686. * Returns array of values that we need for
  687. * the Captcha form.
  688. *
  689. * @return array with 'img' => complete html of img tag,
  690. * 'public_key' value of public key,
  691. * 'hncaptcha' value of hncaptcha
  692. */
  693. public function getCaptchaArray()
  694. {
  695. $aRet = array(
  696. 'img' => $this->display_captcha(),
  697. 'public_key' => $this->getPublicKey(),
  698. 'hncaptcha' => $this->get_try(false));
  699. return $aRet;
  700. }
  701. /**
  702. *
  703. * Create block with Label, Image and
  704. * input for captcha entry
  705. *
  706. * This block can just be dropped into an html template
  707. * of any form
  708. *
  709. * @return string html block with Captcha
  710. */
  711. public function getCaptchaBlock()
  712. {
  713. $aVals = $this->getCaptchaArray();
  714. d('got captcha vals: ' . \json_encode($aVals));
  715. $s = \tplCaptcha::parse($aVals, false);
  716. return $s;
  717. }
  718. }