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