PageRenderTime 63ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/components/com_breezingforms/images/captcha/securimage.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 1603 lines | 694 code | 224 blank | 685 comment | 187 complexity | 652b79fc935c7adce05dacac47238c89 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.0, JSON, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. defined('_JEXEC') or die('Direct Access to this location is not allowed.');
  3. /**
  4. * Project: Securimage: A PHP class for creating and managing form CAPTCHA images<br />
  5. * File: securimage.php<br />
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or any later version.<br /><br />
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.<br /><br />
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA<br /><br />
  20. *
  21. * Any modifications to the library should be indicated clearly in the source code
  22. * to inform users that the changes are not a part of the original software.<br /><br />
  23. *
  24. * If you found this script useful, please take a quick moment to rate it.<br />
  25. * http://www.hotscripts.com/rate/49400.html Thanks.
  26. *
  27. * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
  28. * @link http://www.phpcaptcha.org/latest.zip Download Latest Version
  29. * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
  30. * @copyright 2009 Drew Phillips
  31. * @author Drew Phillips <drew@drew-phillips.com>
  32. * @version 2.0.1 BETA (December 6th, 2009)
  33. * @package Securimage
  34. *
  35. */
  36. /**
  37. ChangeLog
  38. 2.0.2
  39. - Fix pathing to make integration into libraries easier (Nathan Phillip Brink ohnobinki@ohnopublishing.net)
  40. 2.0.1
  41. - Add support for browsers with cookies disabled (requires php5, sqlite) maps users to md5 hashed ip addresses and md5 hashed codes for security
  42. - Add fallback to gd fonts if ttf support is not enabled or font file not found (Mike Challis http://www.642weather.com/weather/scripts.php)
  43. - Check for previous definition of image type constants (Mike Challis)
  44. - Fix mime type settings for audio output
  45. - Fixed color allocation issues with multiple colors and background images, consolidate allocation to one function
  46. - Ability to let codes expire after a given length of time
  47. - Allow HTML color codes to be passed to Securimage_Color (suggested by Mike Challis)
  48. 2.0.0
  49. - Add mathematical distortion to characters (using code from HKCaptcha)
  50. - Improved session support
  51. - Added Securimage_Color class for easier color definitions
  52. - Add distortion to audio output to prevent binary comparison attack (proposed by Sven "SavageTiger" Hagemann [insecurity.nl])
  53. - Flash button to stream mp3 audio (Douglas Walsh www.douglaswalsh.net)
  54. - Audio output is mp3 format by default
  55. - Change font to AlteHaasGrotesk by yann le coroller
  56. - Some code cleanup
  57. 1.0.4 (unreleased)
  58. - Ability to output audible codes in mp3 format to stream from flash
  59. 1.0.3.1
  60. - Error reading from wordlist in some cases caused words to be cut off 1 letter short
  61. 1.0.3
  62. - Removed shadow_text from code which could cause an undefined property error due to removal from previous version
  63. 1.0.2
  64. - Audible CAPTCHA Code wav files
  65. - Create codes from a word list instead of random strings
  66. 1.0
  67. - Added the ability to use a selected character set, rather than a-z0-9 only.
  68. - Added the multi-color text option to use different colors for each letter.
  69. - Switched to automatic session handling instead of using files for code storage
  70. - Added GD Font support if ttf support is not available. Can use internal GD fonts or load new ones.
  71. - Added the ability to set line thickness
  72. - Added option for drawing arced lines over letters
  73. - Added ability to choose image type for output
  74. */
  75. /**
  76. * Output images in JPEG format
  77. */
  78. if (!defined('SI_IMAGE_JPEG'))
  79. define('SI_IMAGE_JPEG', 1);
  80. /**
  81. * Output images in PNG format
  82. */
  83. if (!defined('SI_IMAGE_PNG'))
  84. define('SI_IMAGE_PNG', 2);
  85. /**
  86. * Output images in GIF format (not recommended)
  87. * Must have GD >= 2.0.28!
  88. */
  89. if (!defined('SI_IMAGE_GIF'))
  90. define('SI_IMAGE_GIF', 3);
  91. /**
  92. * Securimage CAPTCHA Class.
  93. *
  94. * @package Securimage
  95. * @subpackage classes
  96. *
  97. */
  98. class Securimage {
  99. /**
  100. * The path which contains securimage.php.
  101. *
  102. * @var string The path to the securimage installation.
  103. */
  104. var $basepath;
  105. /**
  106. * The desired width of the CAPTCHA image.
  107. *
  108. * @var int
  109. */
  110. var $image_width;
  111. /**
  112. * The desired width of the CAPTCHA image.
  113. *
  114. * @var int
  115. */
  116. var $image_height;
  117. /**
  118. * The image format for output.<br />
  119. * Valid options: SI_IMAGE_PNG, SI_IMAGE_JPG, SI_IMAGE_GIF
  120. *
  121. * @var int
  122. */
  123. var $image_type;
  124. /**
  125. * The length of the code to generate.
  126. *
  127. * @var int
  128. */
  129. var $code_length;
  130. /**
  131. * The character set for individual characters in the image.<br />
  132. * Letters are converted to uppercase.<br />
  133. * The font must support the letters or there may be problematic substitutions.
  134. *
  135. * @var string
  136. */
  137. var $charset;
  138. /**
  139. * Create codes using this word list
  140. *
  141. * @var string The path to the word list to use for creating CAPTCHA codes
  142. */
  143. var $wordlist_file;
  144. /**
  145. * Use wordlist of not
  146. *
  147. * @var bool true to use wordlist file, false to use random code
  148. */
  149. var $use_wordlist = false;
  150. /**
  151. * Note: Use of GD fonts is not recommended as many distortion features are not available<br />
  152. * The GD font to use.<br />
  153. * Internal gd fonts can be loaded by their number.<br />
  154. * Alternatively, a file path can be given and the font will be loaded from file.
  155. *
  156. * @var mixed
  157. */
  158. var $gd_font_file;
  159. /**
  160. * The approximate size of the font in pixels.<br />
  161. * This does not control the size of the font because that is determined by the GD font itself.<br />
  162. * This is used to aid the calculations of positioning used by this class.<br />
  163. *
  164. * @var int
  165. */
  166. var $gd_font_size;
  167. /**
  168. * Use a gd font instead of TTF
  169. *
  170. * @var bool true for gd font, false for TTF
  171. */
  172. var $use_gd_font;
  173. // Note: These font options below do not apply if you set $use_gd_font to true with the exception of $text_color
  174. /**
  175. * The path to the TTF font file to load.
  176. *
  177. * @var string
  178. */
  179. var $ttf_file;
  180. /**
  181. * How much to distort image, higher = more distortion.<br />
  182. * Distortion is only available when using TTF fonts.<br />
  183. *
  184. * @var float
  185. */
  186. var $perturbation;
  187. /**
  188. * The minimum angle in degrees, with 0 degrees being left-to-right reading text.<br />
  189. * Higher values represent a counter-clockwise rotation.<br />
  190. * For example, a value of 90 would result in bottom-to-top reading text.<br />
  191. * This value along with maximum angle distance do not need to be very high with perturbation
  192. *
  193. * @var int
  194. */
  195. var $text_angle_minimum;
  196. /**
  197. * The minimum angle in degrees, with 0 degrees being left-to-right reading text.<br />
  198. * Higher values represent a counter-clockwise rotation.<br />
  199. * For example, a value of 90 would result in bottom-to-top reading text.
  200. *
  201. * @var int
  202. */
  203. var $text_angle_maximum;
  204. /**
  205. * The X-Position on the image where letter drawing will begin.<br />
  206. * This value is in pixels from the left side of the image.
  207. *
  208. * @var int
  209. * @deprecated 2.0
  210. */
  211. var $text_x_start;
  212. /**
  213. * The background color for the image as a Securimage_Color.<br />
  214. *
  215. * @var Securimage_Color
  216. */
  217. var $image_bg_color;
  218. /**
  219. * Scan this directory for gif, jpg, and png files to use as background images.<br />
  220. * A random image file will be picked each time.<br />
  221. * Change from null to the full path to your directory.<br />
  222. * i.e. var $background_directory = $_SERVER['DOCUMENT_ROOT'] . '/securimage/backgrounds';
  223. * Make sure not to pass a background image to the show function, otherwise this directive is ignored.
  224. *
  225. * @var string
  226. */
  227. var $background_directory = null; //'./backgrounds';
  228. /**
  229. * The text color to use for drawing characters as a Securimage_Color.<br />
  230. * This value is ignored if $use_multi_text is set to true.<br />
  231. * Make sure this contrasts well with the background color or image.<br />
  232. *
  233. * @see Securimage::$use_multi_text
  234. * @var Securimage_Color
  235. */
  236. var $text_color;
  237. /**
  238. * Set to true to use multiple colors for each character.
  239. *
  240. * @see Securimage::$multi_text_color
  241. * @var boolean
  242. */
  243. var $use_multi_text;
  244. /**
  245. * Array of Securimage_Colors which will be randomly selected for each letter.<br />
  246. *
  247. * @var array
  248. */
  249. var $multi_text_color;
  250. /**
  251. * Set to true to make the characters appear transparent.
  252. *
  253. * @see Securimage::$text_transparency_percentage
  254. * @var boolean
  255. */
  256. var $use_transparent_text;
  257. /**
  258. * The percentage of transparency, 0 to 100.<br />
  259. * A value of 0 is completely opaque, 100 is completely transparent (invisble)
  260. *
  261. * @see Securimage::$use_transparent_text
  262. * @var int
  263. */
  264. var $text_transparency_percentage;
  265. // Line options
  266. /**
  267. * Draw vertical and horizontal lines on the image.
  268. *
  269. * @see Securimage::$line_color
  270. * @see Securimage::$draw_lines_over_text
  271. * @var boolean
  272. */
  273. var $num_lines;
  274. /**
  275. * Color of lines drawn over text
  276. *
  277. * @var string
  278. */
  279. var $line_color;
  280. /**
  281. * Draw the lines over the text.<br />
  282. * If fales lines will be drawn before putting the text on the image.
  283. *
  284. * @var boolean
  285. */
  286. var $draw_lines_over_text;
  287. /**
  288. * Text to write at the bottom corner of captcha image
  289. *
  290. * @since 2.0
  291. * @var string Signature text
  292. */
  293. var $image_signature;
  294. /**
  295. * Color to use for writing signature text
  296. *
  297. * @since 2.0
  298. * @var Securimage_Color
  299. */
  300. var $signature_color;
  301. /**
  302. * Full path to the WAV files to use to make the audio files, include trailing /.<br />
  303. * Name Files [A-Z0-9].wav
  304. *
  305. * @since 1.0.1
  306. * @var string
  307. */
  308. var $audio_path;
  309. /**
  310. * Type of audio file to generate (mp3 or wav)
  311. *
  312. * @var string
  313. */
  314. var $audio_format;
  315. /**
  316. * The session name to use if not the default. Blank for none
  317. *
  318. * @see http://php.net/session_name
  319. * @since 2.0
  320. * @var string
  321. */
  322. var $session_name = '';
  323. /**
  324. * The amount of time in seconds that a code remains valid.<br />
  325. * Any code older than this number will be considered invalid even if entered correctly.<br />
  326. * Any non-numeric or value less than 1 disables this functionality.
  327. *
  328. * @var int
  329. */
  330. var $expiry_time;
  331. /**
  332. * Path to the file to use for storing codes for users.<br />
  333. * THIS FILE MUST ABSOLUTELY NOT BE ACCESSIBLE FROM A WEB BROWSER!!<br />
  334. * Put this file in a directory below the web root or one that is restricted (i.e. an apache .htaccess file with deny from all)<br />
  335. * If you cannot meet those requirements your forms may not be completely protected.<br />
  336. * You could obscure the database file name but this is also not recommended.
  337. *
  338. * @var string
  339. */
  340. var $sqlite_database;
  341. /**
  342. * Use an SQLite database for storing codes as a backup to sessions.<br />
  343. * Note: Sessions will still be used
  344. */
  345. var $use_sqlite_db;
  346. //END USER CONFIGURATION
  347. //There should be no need to edit below unless you really know what you are doing.
  348. /**
  349. * The gd image resource.
  350. *
  351. * @access private
  352. * @var resource
  353. */
  354. var $im;
  355. /**
  356. * Temporary image for rendering
  357. *
  358. * @access private
  359. * @var resource
  360. */
  361. var $tmpimg;
  362. /**
  363. * Internal scale factor for anti-alias @hkcaptcha
  364. *
  365. * @access private
  366. * @since 2.0
  367. * @var int
  368. */
  369. var $iscale; // internal scale factor for anti-alias @hkcaptcha
  370. /**
  371. * The background image resource
  372. *
  373. * @access private
  374. * @var resource
  375. */
  376. var $bgimg;
  377. /**
  378. * The code generated by the script
  379. *
  380. * @access private
  381. * @var string
  382. */
  383. var $code;
  384. /**
  385. * The code that was entered by the user
  386. *
  387. * @access private
  388. * @var string
  389. */
  390. var $code_entered;
  391. /**
  392. * Whether or not the correct code was entered
  393. *
  394. * @access private
  395. * @var boolean
  396. */
  397. var $correct_code;
  398. /**
  399. * Handle to SQLite database
  400. *
  401. * @access private
  402. * @var resource
  403. */
  404. var $sqlite_handle;
  405. /**
  406. * Color resource for image line color
  407. *
  408. * @access private
  409. * @var int
  410. */
  411. var $gdlinecolor;
  412. /**
  413. * Array of colors for multi colored codes
  414. *
  415. * @access private
  416. * @var array
  417. */
  418. var $gdmulticolor;
  419. /**
  420. * Color resource for image font color
  421. *
  422. * @access private
  423. * @var int
  424. */
  425. var $gdtextcolor;
  426. /**
  427. * Color resource for image signature color
  428. *
  429. * @access private
  430. * @var int
  431. */
  432. var $gdsignaturecolor;
  433. /**
  434. * Color resource for image background color
  435. *
  436. * @access private
  437. * @var int
  438. */
  439. var $gdbgcolor;
  440. /**
  441. * Class constructor.<br />
  442. * Because the class uses sessions, this will attempt to start a session if there is no previous one.<br />
  443. * If you do not start a session before calling the class, the constructor must be called before any
  444. * output is sent to the browser.
  445. *
  446. * <code>
  447. * $securimage = new Securimage();
  448. * </code>
  449. *
  450. */
  451. function Securimage()
  452. {
  453. // Initialize session or attach to existing
  454. if ( session_id() == '' ) { // no session has been started yet, which is needed for validation
  455. if (trim($this->session_name) != '') {
  456. session_name($this->session_name); // set session name if provided
  457. }
  458. session_start();
  459. }
  460. // Calculated value
  461. $this->basepath = dirname(__FILE__);
  462. // Set Default Values
  463. $this->image_width = 230;
  464. $this->image_height = 80;
  465. $this->image_type = SI_IMAGE_PNG;
  466. $this->code_length = 6;
  467. $this->charset = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
  468. $this->wordlist_file = $this->basepath . '/words/words.txt';
  469. $this->use_wordlist = false;
  470. $this->gd_font_file = 'gdfonts/automatic.gdf';
  471. $this->use_gd_font = false;
  472. $this->gd_font_size = 24;
  473. $this->text_x_start = 15;
  474. $this->ttf_file = $this->basepath . '/AHGBold.ttf';
  475. $this->perturbation = 0.75;
  476. $this->iscale = 5;
  477. $this->text_angle_minimum = 0;
  478. $this->text_angle_maximum = 0;
  479. $this->image_bg_color = new Securimage_Color(0xff, 0xff, 0xff);
  480. $this->text_color = new Securimage_Color(0x3d, 0x3d, 0x3d);
  481. $this->multi_text_color = array(new Securimage_Color(0x0, 0x20, 0xCC),
  482. new Securimage_Color(0x0, 0x30, 0xEE),
  483. new Securimage_color(0x0, 0x40, 0xCC),
  484. new Securimage_Color(0x0, 0x50, 0xEE),
  485. new Securimage_Color(0x0, 0x60, 0xCC));
  486. $this->use_multi_text = false;
  487. $this->use_transparent_text = false;
  488. $this->text_transparency_percentage = 30;
  489. $this->num_lines = 10;
  490. $this->line_color = new Securimage_Color(0x3d, 0x3d, 0x3d);
  491. $this->draw_lines_over_text = true;
  492. $this->image_signature = '';
  493. $this->signature_color = new Securimage_Color(0x20, 0x50, 0xCC);
  494. $this->signature_font = $this->basepath . '/AHGBold.ttf';
  495. $this->audio_path = $this->basepath . '/audio/';
  496. $this->audio_format = 'mp3';
  497. $this->session_name = '';
  498. $this->expiry_time = 900;
  499. $this->sqlite_database = 'database/securimage.sqlite';
  500. $this->use_sqlite_db = false;
  501. $this->sqlite_handle = false;
  502. }
  503. /**
  504. * Generate a code and output the image to the browser.
  505. *
  506. * <code>
  507. * <?php
  508. * include 'securimage.php';
  509. * $securimage = new Securimage();
  510. * $securimage->show('bg.jpg');
  511. * ?>
  512. * </code>
  513. *
  514. * @param string $background_image The path to an image to use as the background for the CAPTCHA
  515. */
  516. function show($background_image = "")
  517. {
  518. if($background_image != "" && is_readable($background_image)) {
  519. $this->bgimg = $background_image;
  520. }
  521. $this->doImage();
  522. }
  523. /**
  524. * Validate the code entered by the user.
  525. *
  526. * <code>
  527. * $code = $_POST['code'];
  528. * if ($securimage->check($code) == false) {
  529. * die("Sorry, the code entered did not match.");
  530. * } else {
  531. * $valid = true;
  532. * }
  533. * </code>
  534. * @param string $code The code the user entered
  535. * @return boolean true if the code was correct, false if not
  536. */
  537. function check($code)
  538. {
  539. $this->code_entered = $code;
  540. $this->validate();
  541. return $this->correct_code;
  542. }
  543. /**
  544. * Output audio file with HTTP headers to browser
  545. *
  546. * <code>
  547. * $sound = new Securimage();
  548. * $sound->audio_format = 'mp3';
  549. * $sound->outputAudioFile();
  550. * </code>
  551. *
  552. * @since 2.0
  553. */
  554. function outputAudioFile()
  555. {
  556. if (strtolower($this->audio_format) == 'wav') {
  557. header('Content-type: audio/x-wav');
  558. $ext = 'wav';
  559. } else {
  560. header('Content-type: audio/mpeg'); // default to mp3
  561. $ext = 'mp3';
  562. }
  563. header("Content-Disposition: attachment; filename=\"securimage_audio.{$ext}\"");
  564. header('Cache-Control: no-store, no-cache, must-revalidate');
  565. header('Expires: Sun, 1 Jan 2000 12:00:00 GMT');
  566. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
  567. $audio = $this->getAudibleCode($ext);
  568. header('Content-Length: ' . strlen($audio));
  569. echo $audio;
  570. exit;
  571. }
  572. /**
  573. * Generate and output the image
  574. *
  575. * @access private
  576. *
  577. */
  578. function doImage()
  579. {
  580. if ($this->use_gd_font == true) {
  581. $this->iscale = 1;
  582. }
  583. if($this->use_transparent_text == true || $this->bgimg != "") {
  584. $this->im = imagecreatetruecolor($this->image_width, $this->image_height);
  585. $this->tmpimg = imagecreatetruecolor($this->image_width * $this->iscale, $this->image_height * $this->iscale);
  586. } else { //no transparency
  587. $this->im = imagecreate($this->image_width, $this->image_height);
  588. $this->tmpimg = imagecreate($this->image_width * $this->iscale, $this->image_height * $this->iscale);
  589. }
  590. $this->allocateColors();
  591. imagepalettecopy($this->tmpimg, $this->im);
  592. $this->setBackground();
  593. $this->createCode();
  594. if (!$this->draw_lines_over_text && $this->num_lines > 0) $this->drawLines();
  595. $this->drawWord();
  596. if ($this->use_gd_font == false && is_readable($this->ttf_file)) $this->distortedCopy();
  597. if ($this->draw_lines_over_text && $this->num_lines > 0) $this->drawLines();
  598. if (trim($this->image_signature) != '') $this->addSignature();
  599. $this->output();
  600. }
  601. /**
  602. * Allocate all colors that will be used in the CAPTCHA image
  603. *
  604. * @since 2.0.1
  605. * @access private
  606. */
  607. function allocateColors()
  608. {
  609. // allocate bg color first for imagecreate
  610. $this->gdbgcolor = imagecolorallocate($this->im, $this->image_bg_color->r, $this->image_bg_color->g, $this->image_bg_color->b);
  611. $alpha = intval($this->text_transparency_percentage / 100 * 127);
  612. if ($this->use_transparent_text == true) {
  613. $this->gdtextcolor = imagecolorallocatealpha($this->im, $this->text_color->r, $this->text_color->g, $this->text_color->b, $alpha);
  614. $this->gdlinecolor = imagecolorallocatealpha($this->im, $this->line_color->r, $this->line_color->g, $this->line_color->b, $alpha);
  615. } else {
  616. $this->gdtextcolor = imagecolorallocate($this->im, $this->text_color->r, $this->text_color->g, $this->text_color->b);
  617. $this->gdlinecolor = imagecolorallocate($this->im, $this->line_color->r, $this->line_color->g, $this->line_color->b);
  618. }
  619. $this->gdsignaturecolor = imagecolorallocate($this->im, $this->signature_color->r, $this->signature_color->g, $this->signature_color->b);
  620. if ($this->use_multi_text == true) {
  621. $this->gdmulticolor = array();
  622. foreach($this->multi_text_color as $color) {
  623. if ($this->use_transparent_text == true) {
  624. $this->gdmulticolor[] = imagecolorallocatealpha($this->im, $color->r, $color->g, $color->b, $alpha);
  625. } else {
  626. $this->gdmulticolor[] = imagecolorallocate($this->im, $color->r, $color->g, $color->b);
  627. }
  628. }
  629. }
  630. }
  631. /**
  632. * Set the background of the CAPTCHA image
  633. *
  634. * @access private
  635. *
  636. */
  637. function setBackground()
  638. {
  639. imagefilledrectangle($this->im, 0, 0, $this->image_width * $this->iscale, $this->image_height * $this->iscale, $this->gdbgcolor);
  640. imagefilledrectangle($this->tmpimg, 0, 0, $this->image_width * $this->iscale, $this->image_height * $this->iscale, $this->gdbgcolor);
  641. if ($this->bgimg == '') {
  642. if ($this->background_directory != null && is_dir($this->background_directory) && is_readable($this->background_directory)) {
  643. $img = $this->getBackgroundFromDirectory();
  644. if ($img != false) {
  645. $this->bgimg = $img;
  646. }
  647. }
  648. }
  649. $dat = @getimagesize($this->bgimg);
  650. if($dat == false) {
  651. return;
  652. }
  653. switch($dat[2]) {
  654. case 1: $newim = @imagecreatefromgif($this->bgimg); break;
  655. case 2: $newim = @imagecreatefromjpeg($this->bgimg); break;
  656. case 3: $newim = @imagecreatefrompng($this->bgimg); break;
  657. case 15: $newim = @imagecreatefromwbmp($this->bgimg); break;
  658. case 16: $newim = @imagecreatefromxbm($this->bgimg); break;
  659. default: return;
  660. }
  661. if(!$newim) return;
  662. imagecopyresized($this->im, $newim, 0, 0, 0, 0, $this->image_width, $this->image_height, imagesx($newim), imagesy($newim));
  663. }
  664. /**
  665. * Return the full path to a random gif, jpg, or png from the background directory.
  666. *
  667. * @access private
  668. * @see Securimage::$background_directory
  669. * @return mixed false if none found, string $path if found
  670. */
  671. function getBackgroundFromDirectory()
  672. {
  673. $images = array();
  674. if ($dh = opendir($this->background_directory)) {
  675. while (($file = readdir($dh)) !== false) {
  676. if (preg_match('/(jpg|gif|png)$/i', $file)) $images[] = $file;
  677. }
  678. closedir($dh);
  679. if (sizeof($images) > 0) {
  680. return rtrim($this->background_directory, '/') . '/' . $images[rand(0, sizeof($images)-1)];
  681. }
  682. }
  683. return false;
  684. }
  685. /**
  686. * Draw random curvy lines over the image<br />
  687. * Modified code from HKCaptcha
  688. *
  689. * @since 2.0
  690. * @access private
  691. *
  692. */
  693. function drawLines()
  694. {
  695. for ($line = 0; $line < $this->num_lines; ++$line) {
  696. $x = $this->image_width * (1 + $line) / ($this->num_lines + 1);
  697. $x += (0.5 - $this->frand()) * $this->image_width / $this->num_lines;
  698. $y = rand($this->image_height * 0.1, $this->image_height * 0.9);
  699. $theta = ($this->frand()-0.5) * M_PI * 0.7;
  700. $w = $this->image_width;
  701. $len = rand($w * 0.4, $w * 0.7);
  702. $lwid = rand(0, 2);
  703. $k = $this->frand() * 0.6 + 0.2;
  704. $k = $k * $k * 0.5;
  705. $phi = $this->frand() * 6.28;
  706. $step = 0.5;
  707. $dx = $step * cos($theta);
  708. $dy = $step * sin($theta);
  709. $n = $len / $step;
  710. $amp = 1.5 * $this->frand() / ($k + 5.0 / $len);
  711. $x0 = $x - 0.5 * $len * cos($theta);
  712. $y0 = $y - 0.5 * $len * sin($theta);
  713. $ldx = round(-$dy * $lwid);
  714. $ldy = round($dx * $lwid);
  715. for ($i = 0; $i < $n; ++$i) {
  716. $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi);
  717. $y = $y0 + $i * $dy - $amp * $dx * sin($k * $i * $step + $phi);
  718. imagefilledrectangle($this->im, $x, $y, $x + $lwid, $y + $lwid, $this->gdlinecolor);
  719. }
  720. }
  721. }
  722. /**
  723. * Draw the CAPTCHA code over the image
  724. *
  725. * @access private
  726. *
  727. */
  728. function drawWord()
  729. {
  730. $width2 = $this->image_width * $this->iscale;
  731. $height2 = $this->image_height * $this->iscale;
  732. if ($this->use_gd_font == true || !is_readable($this->ttf_file)) {
  733. if (!is_int($this->gd_font_file)) { //is a file name
  734. $font = @imageloadfont($this->gd_font_file);
  735. if ($font == false) {
  736. trigger_error("Failed to load GD Font file {$this->gd_font_file} ", E_USER_WARNING);
  737. return;
  738. }
  739. } else { //gd font identifier
  740. $font = $this->gd_font_file;
  741. }
  742. imagestring($this->im, $font, $this->text_x_start, ($this->image_height / 2) - ($this->gd_font_size / 2), $this->code, $this->gdtextcolor);
  743. } else { //ttf font
  744. $font_size = $height2 * .35;
  745. $bb = imagettfbbox($font_size, 0, $this->ttf_file, $this->code);
  746. $tx = $bb[4] - $bb[0];
  747. $ty = $bb[5] - $bb[1];
  748. $x = floor($width2 / 2 - $tx / 2 - $bb[0]);
  749. $y = round($height2 / 2 - $ty / 2 - $bb[1]);
  750. $strlen = strlen($this->code);
  751. if (!is_array($this->multi_text_color)) $this->use_multi_text = false;
  752. if ($this->use_multi_text == false && $this->text_angle_minimum == 0 && $this->text_angle_maximum == 0) { // no angled or multi-color characters
  753. imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code);
  754. } else {
  755. for($i = 0; $i < $strlen; ++$i) {
  756. $angle = rand($this->text_angle_minimum, $this->text_angle_maximum);
  757. $y = rand($y - 5, $y + 5);
  758. if ($this->use_multi_text == true) {
  759. $font_color = $this->gdmulticolor[rand(0, sizeof($this->gdmulticolor) - 1)];
  760. } else {
  761. $font_color = $this->gdtextcolor;
  762. }
  763. $ch = $this->code{$i};
  764. imagettftext($this->tmpimg, $font_size, $angle, $x, $y, $font_color, $this->ttf_file, $ch);
  765. // estimate character widths to increment $x without creating spaces that are too large or too small
  766. // these are best estimates to align text but may vary between fonts
  767. // for optimal character widths, do not use multiple text colors or character angles and the complete string will be written by imagettftext
  768. if (strpos('abcdeghknopqsuvxyz', $ch) !== false) {
  769. $min_x = $font_size - ($this->iscale * 6);
  770. $max_x = $font_size - ($this->iscale * 6);
  771. } else if (strpos('ilI1', $ch) !== false) {
  772. $min_x = $font_size / 5;
  773. $max_x = $font_size / 3;
  774. } else if (strpos('fjrt', $ch) !== false) {
  775. $min_x = $font_size - ($this->iscale * 12);
  776. $max_x = $font_size - ($this->iscale * 12);
  777. } else if ($ch == 'wm') {
  778. $min_x = $font_size;
  779. $max_x = $font_size + ($this->iscale * 3);
  780. } else { // numbers, capitals or unicode
  781. $min_x = $font_size + ($this->iscale * 2);
  782. $max_x = $font_size + ($this->iscale * 5);
  783. }
  784. $x += rand($min_x, $max_x);
  785. } //for loop
  786. } // angled or multi-color
  787. } //else ttf font
  788. //$this->im = $this->tmpimg;
  789. //$this->output();
  790. } //function
  791. /**
  792. * Warp text from temporary image onto final image.<br />
  793. * Modified for securimage
  794. *
  795. * @access private
  796. * @since 2.0
  797. * @author Han-Kwang Nienhuys modified
  798. * @copyright Han-Kwang Neinhuys
  799. *
  800. */
  801. function distortedCopy()
  802. {
  803. $numpoles = 3; // distortion factor
  804. // make array of poles AKA attractor points
  805. for ($i = 0; $i < $numpoles; ++$i) {
  806. $px[$i] = rand($this->image_width * 0.3, $this->image_width * 0.7);
  807. $py[$i] = rand($this->image_height * 0.3, $this->image_height * 0.7);
  808. $rad[$i] = rand($this->image_width * 0.4, $this->image_width * 0.7);
  809. $tmp = -$this->frand() * 0.15 - 0.15;
  810. $amp[$i] = $this->perturbation * $tmp;
  811. }
  812. $bgCol = imagecolorat($this->tmpimg, 0, 0);
  813. $width2 = $this->iscale * $this->image_width;
  814. $height2 = $this->iscale * $this->image_height;
  815. imagepalettecopy($this->im, $this->tmpimg); // copy palette to final image so text colors come across
  816. // loop over $img pixels, take pixels from $tmpimg with distortion field
  817. for ($ix = 0; $ix < $this->image_width; ++$ix) {
  818. for ($iy = 0; $iy < $this->image_height; ++$iy) {
  819. $x = $ix;
  820. $y = $iy;
  821. for ($i = 0; $i < $numpoles; ++$i) {
  822. $dx = $ix - $px[$i];
  823. $dy = $iy - $py[$i];
  824. if ($dx == 0 && $dy == 0) continue;
  825. $r = sqrt($dx * $dx + $dy * $dy);
  826. if ($r > $rad[$i]) continue;
  827. $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
  828. $x += $dx * $rscale;
  829. $y += $dy * $rscale;
  830. }
  831. $c = $bgCol;
  832. $x *= $this->iscale;
  833. $y *= $this->iscale;
  834. if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
  835. $c = imagecolorat($this->tmpimg, $x, $y);
  836. }
  837. if ($c != $bgCol) { // only copy pixels of letters to preserve any background image
  838. imagesetpixel($this->im, $ix, $iy, $c);
  839. }
  840. }
  841. }
  842. }
  843. /**
  844. * Create a code and save to the session
  845. *
  846. * @access private
  847. * @since 1.0.1
  848. *
  849. */
  850. function createCode()
  851. {
  852. $this->code = false;
  853. if ($this->use_wordlist && is_readable($this->wordlist_file)) {
  854. $this->code = $this->readCodeFromFile();
  855. }
  856. if ($this->code == false) {
  857. $this->code = $this->generateCode($this->code_length);
  858. }
  859. $this->saveData();
  860. }
  861. /**
  862. * Generate a code
  863. *
  864. * @access private
  865. * @param int $len The code length
  866. * @return string
  867. */
  868. function generateCode($len)
  869. {
  870. $code = '';
  871. for($i = 1, $cslen = strlen($this->charset); $i <= $len; ++$i) {
  872. $code .= $this->charset{rand(0, $cslen - 1)};
  873. }
  874. return $code;
  875. }
  876. /**
  877. * Reads a word list file to get a code
  878. *
  879. * @access private
  880. * @since 1.0.2
  881. * @return mixed false on failure, a word on success
  882. */
  883. function readCodeFromFile()
  884. {
  885. $fp = @fopen($this->wordlist_file, 'rb');
  886. if (!$fp) return false;
  887. $fsize = filesize($this->wordlist_file);
  888. if ($fsize < 32) return false; // too small of a list to be effective
  889. if ($fsize < 128) {
  890. $max = $fsize; // still pretty small but changes the range of seeking
  891. } else {
  892. $max = 128;
  893. }
  894. fseek($fp, rand(0, $fsize - $max), SEEK_SET);
  895. $data = fread($fp, 128); // read a random 128 bytes from file
  896. fclose($fp);
  897. $data = preg_replace("/\r?\n/", "\n", $data);
  898. $start = strpos($data, "\n", rand(0, 100)) + 1; // random start position
  899. $end = strpos($data, "\n", $start); // find end of word
  900. return strtolower(substr($data, $start, $end - $start)); // return substring in 128 bytes
  901. }
  902. /**
  903. * Output image to the browser
  904. *
  905. * @access private
  906. *
  907. */
  908. function output()
  909. {
  910. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  911. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT");
  912. header("Cache-Control: no-store, no-cache, must-revalidate");
  913. header("Cache-Control: post-check=0, pre-check=0", false);
  914. header("Pragma: no-cache");
  915. switch($this->image_type)
  916. {
  917. case SI_IMAGE_JPEG:
  918. header("Content-Type: image/jpeg");
  919. imagejpeg($this->im, null, 90);
  920. break;
  921. case SI_IMAGE_GIF:
  922. header("Content-Type: image/gif");
  923. imagegif($this->im);
  924. break;
  925. default:
  926. header("Content-Type: image/png");
  927. imagepng($this->im);
  928. break;
  929. }
  930. imagedestroy($this->im);
  931. exit;
  932. }
  933. /**
  934. * Get WAV or MP3 file data of the spoken code.<br />
  935. * This is appropriate for output to the browser as audio/x-wav or audio/mpeg
  936. *
  937. * @since 1.0.1
  938. * @return string WAV or MP3 data
  939. *
  940. */
  941. function getAudibleCode($format = 'wav')
  942. {
  943. $letters = array();
  944. $code = $this->getCode();
  945. if ($code == '') {
  946. $this->createCode();
  947. $code = $this->getCode();
  948. }
  949. for($i = 0; $i < strlen($code); ++$i) {
  950. $letters[] = $code{$i};
  951. }
  952. if ($format == 'mp3') {
  953. return $this->generateMP3($letters);
  954. } else {
  955. return $this->generateWAV($letters);
  956. }
  957. }
  958. /**
  959. * Set the path to the audio directory.<br />
  960. *
  961. * @since 1.0.4
  962. * @return bool true if the directory exists and is readble, false if not
  963. */
  964. function setAudioPath($audio_directory)
  965. {
  966. if (is_dir($audio_directory) && is_readable($audio_directory)) {
  967. $this->audio_path = $audio_directory;
  968. return true;
  969. } else {
  970. return false;
  971. }
  972. }
  973. /**
  974. * Save the code in the session
  975. *
  976. * @access private
  977. *
  978. */
  979. function saveData()
  980. {
  981. $_SESSION['securimage_code_tries'] = 0;
  982. $_SESSION['securimage_code_value'] = strtolower($this->code);
  983. $_SESSION['securimage_code_ctime'] = time();
  984. $this->saveCodeToDatabase();
  985. }
  986. /**
  987. * Validate the code to the user code
  988. *
  989. * @access private
  990. *
  991. */
  992. function validate()
  993. {
  994. // retrieve code from session, if no code exists check sqlite database if supported.
  995. $code = '';
  996. if (isset($_SESSION['securimage_code_value']) && trim($_SESSION['securimage_code_value']) != '') {
  997. if ($this->isCodeExpired($_SESSION['securimage_code_ctime']) == false) {
  998. $code = $_SESSION['securimage_code_value'];
  999. }
  1000. } else if ($this->use_sqlite_db == true && function_exists('sqlite_open')) { // no code in session - may mean user has cookies turned off
  1001. $this->openDatabase();
  1002. $code = $this->getCodeFromDatabase();
  1003. } else { /* session code invalid or non-existant and code not found in sqlite db or sqlite is not available */ }
  1004. $code = trim(strtolower($code));
  1005. $code_entered = trim(strtolower($this->code_entered));
  1006. $this->correct_code = false;
  1007. if ($code != '') {
  1008. if ($code == $code_entered) {
  1009. $this->correct_code = true;
  1010. if(!isset($_SESSION['securimage_code_tries'])){
  1011. $_SESSION['securimage_code_tries'] = 0;
  1012. }
  1013. $_SESSION['securimage_code_tries']++;
  1014. if($_SESSION['securimage_code_tries'] > 1){
  1015. $_SESSION['securimage_code_value'] = '';
  1016. $_SESSION['securimage_code_ctime'] = '';
  1017. $_SESSION['securimage_code_tries'] = 0;
  1018. $this->clearCodeFromDatabase();
  1019. }
  1020. }
  1021. }
  1022. }
  1023. /**
  1024. * Get the captcha code
  1025. *
  1026. * @since 1.0.1
  1027. * @return string
  1028. */
  1029. function getCode()
  1030. {
  1031. if (isset($_SESSION['securimage_code_value']) && !empty($_SESSION['securimage_code_value'])) {
  1032. return strtolower($_SESSION['securimage_code_value']);
  1033. } else {
  1034. if ($this->sqlite_handle == false) $this->openDatabase();
  1035. return $this->getCodeFromDatabase(); // attempt to get from database, returns empty string if sqlite is not available or disabled
  1036. }
  1037. }
  1038. /**
  1039. * Check if the user entered code was correct
  1040. *
  1041. * @access private
  1042. * @return boolean
  1043. */
  1044. function checkCode()
  1045. {
  1046. return $this->correct_code;
  1047. }
  1048. /**
  1049. * Generate a wav file by concatenating individual files
  1050. *
  1051. * @since 1.0.1
  1052. * @access private
  1053. * @param array $letters Array of letters to build a file from
  1054. * @return string WAV file data
  1055. */
  1056. function generateWAV($letters)
  1057. {
  1058. $data_len = 0;
  1059. $files = array();
  1060. $out_data = '';
  1061. foreach ($letters as $letter) {
  1062. $filename = $this->audio_path . strtoupper($letter) . '.wav';
  1063. $fp = fopen($filename, 'rb');
  1064. $file = array();
  1065. $data = fread($fp, filesize($filename)); // read file in
  1066. $header = substr($data, 0, 36);
  1067. $body = substr($data, 44);
  1068. $data = unpack('NChunkID/VChunkSize/NFormat/NSubChunk1ID/VSubChunk1Size/vAudioFormat/vNumChannels/VSampleRate/VByteRate/vBlockAlign/vBitsPerSample', $header);
  1069. $file['sub_chunk1_id'] = $data['SubChunk1ID'];
  1070. $file['bits_per_sample'] = $data['BitsPerSample'];
  1071. $file['channels'] = $data['NumChannels'];
  1072. $file['format'] = $data['AudioFormat'];
  1073. $file['sample_rate'] = $data['SampleRate'];
  1074. $file['size'] = $data['ChunkSize'] + 8;
  1075. $file['data'] = $body;
  1076. if ( ($p = strpos($file['data'], 'LIST')) !== false) {
  1077. // If the LIST data is not at the end of the file, this will probably break your sound file
  1078. $info = substr($file['data'], $p + 4, 8);
  1079. $data = unpack('Vlength/Vjunk', $info);
  1080. $file['data'] = substr($file['data'], 0, $p);
  1081. $file['size'] = $file['size'] - (strlen($file['data']) - $p);
  1082. }
  1083. $files[] = $file;
  1084. $data = null;
  1085. $header = null;
  1086. $body = null;
  1087. $data_len += strlen($file['data']);
  1088. fclose($fp);
  1089. }
  1090. $out_data = '';
  1091. for($i = 0; $i < sizeof($files); ++$i) {
  1092. if ($i == 0) { // output header
  1093. $out_data .= pack('C4VC8', ord('R'), ord('I'), ord('F'), ord('F'), $data_len + 36, ord('W'), ord('A'), ord('V'), ord('E'), ord('f'), ord('m'), ord('t'), ord(' '));
  1094. $out_data .= pack('VvvVVvv',
  1095. 16,
  1096. $files[$i]['format'],
  1097. $files[$i]['channels'],
  1098. $files[$i]['sample_rate'],
  1099. $files[$i]['sample_rate'] * (($files[$i]['bits_per_sample'] * $files[$i]['channels']) / 8),
  1100. ($files[$i]['bits_per_sample'] * $files[$i]['channels']) / 8,
  1101. $files[$i]['bits_per_sample'] );
  1102. $out_data .= pack('C4', ord('d'), ord('a'), ord('t'), ord('a'));
  1103. $out_data .= pack('V', $data_len);
  1104. }
  1105. $out_data .= $files[$i]['data'];
  1106. }
  1107. $this->scrambleAudioData($out_data, 'wav');
  1108. return $out_data;
  1109. }
  1110. /**
  1111. * Randomly modify the audio data to scramble sound and prevent binary recognition.<br />
  1112. * Take care not to "break" the audio file by leaving the header data intact.
  1113. *
  1114. * @since 2.0
  1115. * @access private
  1116. * @param $data Sound data in mp3 of wav format
  1117. */
  1118. function scrambleAudioData(&$data, $format)
  1119. {
  1120. if ($format == 'wav') {
  1121. $start = strpos($data, 'data') + 4; // look for "data" indicator
  1122. if ($start === false) $start = 44; // if not found assume 44 byte header
  1123. } else { // mp3
  1124. $start = 4; // 4 byte (32 bit) frame header
  1125. }
  1126. $start += rand(1, 64); // randomize starting offset
  1127. $datalen = strlen($data) - $start - 256; // leave last 256 bytes unchanged
  1128. for ($i = $start; $i < $datalen; $i += 64) {
  1129. $ch = ord($data{$i});
  1130. if ($ch < 9 || $ch > 119) continue;
  1131. $data{$i} = chr($ch + rand(-8, 8));
  1132. }
  1133. }
  1134. /**
  1135. * Generate an mp3 file by concatenating individual files
  1136. * @since 1.0.4
  1137. * @access private
  1138. * @param array $letters Array of letters to build a file from
  1139. * @return string MP3 file data
  1140. */
  1141. function generateMP3($letters)
  1142. {
  1143. $data_len = 0;
  1144. $files = array();
  1145. $out_data = '';
  1146. foreach ($letters as $letter) {
  1147. $filename = $this->audio_path . strtoupper($letter) . '.mp3';
  1148. $fp = fopen($filename, 'rb');
  1149. $data = fread($fp, filesize($filename)); // read file in
  1150. $this->scrambleAudioData($data, 'mp3');
  1151. $out_data .= $data;
  1152. fclose($fp);
  1153. }
  1154. return $out_data;
  1155. }
  1156. /**
  1157. * Generate random number less than 1
  1158. * @since 2.0
  1159. * @access private
  1160. * @return float
  1161. */
  1162. function frand()
  1163. {
  1164. return 0.0001*rand(0,9999);
  1165. }
  1166. /**
  1167. * Print signature text on image
  1168. *
  1169. * @since 2.0
  1170. * @access private
  1171. *
  1172. */
  1173. function addSignature()
  1174. {
  1175. if ($this->use_gd_font) {
  1176. imagestring($this->im, 5, $this->image_width - (strlen($this->image_signature) * 10), $this->image_height - 20, $this->image_signature, $this->gdsignaturecolor);
  1177. } else {
  1178. $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature);
  1179. $textlen = $bbox[2] - $bbox[0];
  1180. $x = $this->image_width - $textlen - 5;
  1181. $y = $this->image_height - 3;
  1182. imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature);
  1183. }
  1184. }
  1185. /**
  1186. * Get hashed IP address of remote user
  1187. *
  1188. * @access private
  1189. * @since 2.0.1
  1190. * @return string
  1191. */
  1192. function getIPHash()
  1193. {
  1194. return strtolower(md5($_SERVER['REMOTE_ADDR']));
  1195. }
  1196. /**
  1197. * Open SQLite database
  1198. *
  1199. * @access private
  1200. * @since 2.0.1
  1201. * @return bool true if database was opened successfully
  1202. */
  1203. function openDatabase()
  1204. {
  1205. $this->sqlite_handle = false;
  1206. if ($this->use_sqlite_db && function_exists('sqlite_open')) {
  1207. $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666, $error);
  1208. if ($this->sqlite_handle !== false) {
  1209. $res = sqlite_query($this->sqlite_handle, "PRAGMA table_info(codes)");
  1210. if (sqlite_num_rows($res) == 0) {
  1211. sqlite_query($this->sqlite_handle, "CREATE TABLE codes (iphash VARCHAR(32) PRIMARY KEY, code VARCHAR(32) NOT NULL, created INTEGER)");
  1212. }
  1213. }
  1214. return $this->sqlite_handle != false;
  1215. }
  1216. return $this->sqlite_handle;
  1217. }
  1218. /**
  1219. * Save captcha code to sqlite database
  1220. *
  1221. * @access private
  1222. * @since 2.0.1
  1223. * @return bool true if code was saved, false if not
  1224. */
  1225. function saveCodeToDatabase()
  1226. {
  1227. $success = false;
  1228. $this->openDatabase();
  1229. if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
  1230. $ip = $this->getIPHash();
  1231. $time = time();
  1232. $code = $_SESSION['securimage_code_value']; // hash code for security - if cookies are disabled the session still exists at this point
  1233. $success = sqlite_query($this->sqlite_handle, "INSERT OR REPLACE INTO codes(iphash, code, created) VALUES('$ip', '$code', $time)");
  1234. }
  1235. return $success !== false;
  1236. }
  1237. /**
  1238. * Get stored captcha code from sqlite database based on ip address hash
  1239. *
  1240. * @access private
  1241. * @since 2.0.1
  1242. * @return string captcha code
  1243. */
  1244. function getCodeFromDatabase()
  1245. {
  1246. $code = '';
  1247. if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
  1248. $ip = $this->getIPHash();
  1249. $res = sqlite_query($this->sqlite_handle, "SELECT * FROM codes WHERE iphash = '$ip'");
  1250. if ($res && sqlite_num_rows($res) > 0) {
  1251. $res = sqlite_fetch_array($res);
  1252. if ($this->isCodeExpired($res['created']) == false) {
  1253. $code = $res['code'];
  1254. }
  1255. }
  1256. }
  1257. return $code;
  1258. }
  1259. /**
  1260. * Delete a code from the database by ip address hash
  1261. *
  1262. * @access private
  1263. * @since 2.0.1
  1264. */
  1265. function clearCodeFromDatabase()
  1266. {
  1267. if ($this->sqlite_handle !== false) {
  1268. $ip = $this->getIPHash();
  1269. sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE iphash = '$ip'");
  1270. }
  1271. }
  1272. /**
  1273. * Purge codes over a day old from database
  1274. *
  1275. * @access private
  1276. * @since 2.0.1
  1277. */
  1278. function purgeOldCodesFromDatabase()
  1279. {
  1280. if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
  1281. $now = time();
  1282. $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
  1283. sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE $now - created > $limit");
  1284. }
  1285. }
  1286. /**
  1287. * Check a code to see if it is expired based on creation time
  1288. *
  1289. * @access private
  1290. * @since 2.0.1
  1291. * @param $creation_time unix timestamp of code creation time
  1292. * @return bool true if code has expired, false if not
  1293. */
  1294. function isCodeExpired($creation_time)
  1295. {
  1296. $expired = true;
  1297. if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
  1298. $expired = false;
  1299. } else if (time() - $creation_time < $this->expiry_time) {
  1300. $expired = false;
  1301. }
  1302. return $expired;
  1303. }
  1304. } /* class Securimage */
  1305. /**
  1306. * Color object for Securimage CAPTCHA
  1307. *
  1308. * @since 2.0
  1309. * @package Securimage
  1310. * @subpackage classes
  1311. *
  1312. */
  1313. class Securimage_Color {
  1314. /**
  1315. * Red component: 0-255
  1316. *
  1317. * @var int
  1318. */
  1319. var $r;
  1320. /**
  1321. * Green component: 0-255
  1322. *
  1323. * @var int
  1324. */
  1325. var $g;
  1326. /**
  1327. * Blue component: 0-255
  1328. *
  1329. * @var int
  1330. */
  1331. var $b;
  1332. /**
  1333. * Create a new Securimage_Color object.<br />
  1334. * Specify the red, green, and blue components using their HTML hex code equivalent.<br />
  1335. * Example: The code for the HTML color #4A203C is:<br />
  1336. * $color = new Securimage_Color(0x4A, 0x20, 0x3C);
  1337. *
  1338. * @param $red Red component 0-255
  1339. * @param $green Green component 0-255
  1340. * @param $blue Blue component 0-255
  1341. */
  1342. function Securimage_Color($red, $green = null, $blue = null)
  1343. {
  1344. if ($green == null && $blue == null && preg_match('/^#[a-f0-9]{3,6}$/i', $red)) {
  1345. $col = substr($red, 1);
  1346. if (strlen($col) == 3) {
  1347. $red = str_repeat(substr($col, 0, 1), 2);
  1348. $green = str_repeat(substr($col, 1, 1), 2);
  1349. $blue = str_repeat(substr($col, 2, 1), 2);
  1350. } else {
  1351. $red = substr($col, 0, 2);
  1352. $green = substr($col, 2, 2);
  1353. $blue = substr($col, 4, 2);
  1354. }
  1355. $red = hexdec($red);
  1356. $green = hexdec($green);
  1357. $blue = hexdec($blue);
  1358. } else {
  1359. if ($red < 0) $red = 0;
  1360. if ($red > 255) $red = 255;
  1361. if ($green < 0) $green = 0;
  1362. if ($green > 255) $green = 255;
  1363. if

Large files files are truncated, but you can click here to view the full file