ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
securimage.php
Go to the documentation of this file.
1<?php
2
3// error_reporting(E_ALL); ini_set('display_errors', 1); // uncomment this line for debugging
4
166{
167 // All of the public variables below are securimage options
168 // They can be passed as an array to the Securimage constructor, set below,
169 // or set from securimage_show.php and securimage_play.php
170
175 const SI_IMAGE_JPEG = 1;
180 const SI_IMAGE_PNG = 2;
185 const SI_IMAGE_GIF = 3;
186
202
208 const SI_DRIVER_MYSQL = 'mysql';
209
215 const SI_DRIVER_PGSQL = 'pgsql';
216
222 const SI_DRIVER_SQLITE3 = 'sqlite';
223
224 /*%*********************************************************************%*/
225 // Properties
226
231 public $image_width = 215;
236 public $image_height = 80;
242
247 public $image_bg_color = '#ffffff';
252 public $text_color = '#707070';
257 public $line_color = '#707070';
262 public $noise_color = '#707070';
263
274
279 public $code_length = 6;
284 public $case_sensitive = false;
289 public $charset = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
294 public $expiry_time = 900;
295
301 public $session_name = null;
302
307 public $use_wordlist = false;
308
313 public $perturbation = 0.85;
318 public $num_lines = 5;
323 public $noise_level = 2;
324
329 public $image_signature = '';
334 public $signature_color = '#707070';
340
348 public $use_sqlite_db = false;
349
358 public $use_database = false;
359
368
376 public $database_host = 'localhost';
377
384 public $database_user = '';
385
392 public $database_pass = '';
393
400 public $database_name = '';
401
409 public $database_table = 'captcha_codes';
410
419
425 public $captcha_type = self::SI_CAPTCHA_STRING; // or self::SI_CAPTCHA_MATHEMATIC;
426
443
448 public $ttf_file;
526 public $audio_gap_min = 0;
533 public $audio_gap_max = 600;
534
539 protected static $_captchaId = null;
540
541 protected $im;
542 protected $tmpimg;
543 protected $bgimg;
544 protected $iscale = 5;
545
546 public $securimage_path = null;
547
553 protected $code;
554
560 protected $code_display;
561
571
577 protected $captcha_code;
578
584 protected $no_exit;
585
591 protected $no_session;
592
598 protected $send_headers;
599
605 protected $pdo_conn;
606
607 // gd color resources that are allocated for drawing the image
608 protected $gdbgcolor;
609 protected $gdtextcolor;
610 protected $gdlinecolor;
612
629 public function __construct($options = array())
630 {
631 $this->securimage_path = dirname(__FILE__);
632
633 if (is_array($options) && sizeof($options) > 0) {
634 foreach($options as $prop => $val) {
635 if ($prop == 'captchaId') {
637 $this->use_database = true;
638 } else if ($prop == 'use_sqlite_db') {
639 trigger_error("The use_sqlite_db option is deprecated, use 'use_database' instead", E_USER_NOTICE);
640 } else {
641 $this->$prop = $val;
642 }
643 }
644 }
645
646 $this->image_bg_color = $this->initColor($this->image_bg_color, '#ffffff');
647 $this->text_color = $this->initColor($this->text_color, '#616161');
648 $this->line_color = $this->initColor($this->line_color, '#616161');
649 $this->noise_color = $this->initColor($this->noise_color, '#616161');
650 $this->signature_color = $this->initColor($this->signature_color, '#616161');
651
652 if (is_null($this->ttf_file)) {
653 $this->ttf_file = $this->securimage_path . '/AHGBold.ttf';
654 }
655
656 $this->signature_font = $this->ttf_file;
657
658 if (is_null($this->wordlist_file)) {
659 $this->wordlist_file = $this->securimage_path . '/words/words.txt';
660 }
661
662 if (is_null($this->database_file)) {
663 $this->database_file = $this->securimage_path . '/database/securimage.sq3';
664 }
665
666 if (is_null($this->audio_path)) {
667 $this->audio_path = $this->securimage_path . '/audio/en/';
668 }
669
670 if (is_null($this->audio_noise_path)) {
671 $this->audio_noise_path = $this->securimage_path . '/audio/noise/';
672 }
673
674 if (is_null($this->audio_use_noise)) {
675 $this->audio_use_noise = true;
676 }
677
678 if (is_null($this->degrade_audio)) {
679 $this->degrade_audio = true;
680 }
681
682 if (is_null($this->code_length) || (int)$this->code_length < 1) {
683 $this->code_length = 6;
684 }
685
686 if (is_null($this->perturbation) || !is_numeric($this->perturbation)) {
687 $this->perturbation = 0.75;
688 }
689
690 if (is_null($this->namespace) || !is_string($this->namespace)) {
691 $this->namespace = 'default';
692 }
693
694 if (is_null($this->no_exit)) {
695 $this->no_exit = false;
696 }
697
698 if (is_null($this->no_session)) {
699 $this->no_session = false;
700 }
701
702 if (is_null($this->send_headers)) {
703 $this->send_headers = true;
704 }
705
706 if ($this->no_session != true) {
707 // Initialize session or attach to existing
708 if ( session_id() == '' ) { // no session has been started yet, which is needed for validation
709 if (!is_null($this->session_name) && trim($this->session_name) != '') {
710 session_name(trim($this->session_name)); // set session name if provided
711 }
712 session_start();
713 }
714 }
715 }
716
721 public static function getPath()
722 {
723 return dirname(__FILE__);
724 }
725
735 public static function getCaptchaId($new = true, array $options = array())
736 {
737 if (is_null($new) || (bool)$new == true) {
738 $id = sha1(uniqid($_SERVER['REMOTE_ADDR'], true));
739 $opts = array('no_session' => true,
740 'use_database' => true);
741 if (sizeof($options) > 0) $opts = array_merge($options, $opts);
742 $si = new self($opts);
744 $si->createCode();
745
746 return $id;
747 } else {
749 }
750 }
751
763 public static function checkByCaptchaId($id, $value, array $options = array())
764 {
765 $opts = array('captchaId' => $id,
766 'no_session' => true,
767 'use_database' => true);
768
769 if (sizeof($options) > 0) $opts = array_merge($options, $opts);
770
771 $si = new self($opts);
772
773 if ($si->openDatabase()) {
774 $code = $si->getCodeFromDatabase();
775
776 if (is_array($code)) {
777 $si->code = $code['code'];
778 $si->code_display = $code['code_disp'];
779 }
780
781 if ($si->check($value)) {
782 $si->clearCodeFromDatabase();
783
784 return true;
785 } else {
786 return false;
787 }
788 } else {
789 return false;
790 }
791 }
792
793
807 public function show($background_image = '')
808 {
809 set_error_handler(array(&$this, 'errorHandler'));
810
811 if($background_image != '' && is_readable($background_image)) {
812 $this->bgimg = $background_image;
813 }
814
815 $this->doImage();
816 }
817
831 public function check($code)
832 {
833 $this->code_entered = $code;
834 $this->validate();
835 return $this->correct_code;
836 }
837
847 public function outputAudioFile()
848 {
849 set_error_handler(array(&$this, 'errorHandler'));
850
851 require_once dirname(__FILE__) . '/WavFile.php';
852
853 try {
854 $audio = $this->getAudibleCode();
855 } catch (Exception $ex) {
856 if (($fp = @fopen(dirname(__FILE__) . '/si.error_log', 'a+')) !== false) {
857 fwrite($fp, date('Y-m-d H:i:s') . ': Securimage audio error "' . $ex->getMessage() . '"' . "\n");
858 fclose($fp);
859 }
860
861 $audio = $this->audioError();
862 }
863
864 if ($this->canSendHeaders() || $this->send_headers == false) {
865 if ($this->send_headers) {
866 $uniq = md5(uniqid(microtime()));
867 header("Content-Disposition: attachment; filename=\"securimage_audio-{$uniq}.wav\"");
868 header('Cache-Control: no-store, no-cache, must-revalidate');
869 header('Expires: Sun, 1 Jan 2000 12:00:00 GMT');
870 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
871 header('Content-type: audio/x-wav');
872
873 if (extension_loaded('zlib')) {
874 ini_set('zlib.output_compression', true); // compress output if supported by browser
875 } else {
876 header('Content-Length: ' . strlen($audio));
877 }
878 }
879
880 echo $audio;
881 } else {
882 echo '<hr /><strong>'
883 .'Failed to generate audio file, content has already been '
884 .'output.<br />This is most likely due to misconfiguration or '
885 .'a PHP error was sent to the browser.</strong>';
886 }
887
888 restore_error_handler();
889
890 if (!$this->no_exit) exit;
891 }
892
899 public function getCode($array = false, $returnExisting = false)
900 {
901 $code = '';
902 $time = 0;
903 $disp = 'error';
904
905 if ($returnExisting && strlen($this->code) > 0) {
906 if ($array) {
907 return array('code' => $this->code,
908 'display' => $this->code_display,
909 'code_display' => $this->code_display,
910 'time' => 0);
911 } else {
912 return $this->code;
913 }
914 }
915
916 if ($this->no_session != true) {
917 if (isset($_SESSION['securimage_code_value'][$this->namespace]) &&
918 trim($_SESSION['securimage_code_value'][$this->namespace]) != '') {
919 if ($this->isCodeExpired(
920 $_SESSION['securimage_code_ctime'][$this->namespace]) == false) {
921 $code = $_SESSION['securimage_code_value'][$this->namespace];
922 $time = $_SESSION['securimage_code_ctime'][$this->namespace];
923 $disp = $_SESSION['securimage_code_disp'] [$this->namespace];
924 }
925 }
926 }
927
928 if (empty($code) && $this->use_database) {
929 // no code in session - may mean user has cookies turned off
930 $this->openDatabase();
931 $code = $this->getCodeFromDatabase();
932 } else { /* no code stored in session or sqlite database, validation will fail */ }
933
934 if ($array == true) {
935 return array('code' => $code, 'ctime' => $time, 'display' => $disp);
936 } else {
937 return $code;
938 }
939 }
940
944 protected function doImage()
945 {
946 if( ($this->use_transparent_text == true || $this->bgimg != '') && function_exists('imagecreatetruecolor')) {
947 $imagecreate = 'imagecreatetruecolor';
948 } else {
949 $imagecreate = 'imagecreate';
950 }
951
952 $this->im = $imagecreate($this->image_width, $this->image_height);
953 $this->tmpimg = $imagecreate($this->image_width * $this->iscale, $this->image_height * $this->iscale);
954
955 $this->allocateColors();
956 imagepalettecopy($this->tmpimg, $this->im);
957
958 $this->setBackground();
959
960 $code = '';
961
962 if ($this->getCaptchaId(false) !== null) {
963 // a captcha Id was supplied
964
965 // check to see if a display_value for the captcha image was set
966 if (is_string($this->display_value) && strlen($this->display_value) > 0) {
967 $this->code_display = $this->display_value;
968 $this->code = ($this->case_sensitive) ?
969 $this->display_value :
970 strtolower($this->display_value);
972 } else if ($this->openDatabase()) {
973 // no display_value, check the database for existing captchaId
974 $code = $this->getCodeFromDatabase();
975
976 // got back a result from the database with a valid code for captchaId
977 if (is_array($code)) {
978 $this->code = $code['code'];
979 $this->code_display = $code['code_disp'];
980 $code = $code['code'];
981 }
982 }
983 }
984
985 if ($code == '') {
986 // if the code was not set using display_value or was not found in
987 // the database, create a new code
988 $this->createCode();
989 }
990
991 if ($this->noise_level > 0) {
992 $this->drawNoise();
993 }
994
995 $this->drawWord();
996
997 if ($this->perturbation > 0 && is_readable($this->ttf_file)) {
998 $this->distortedCopy();
999 }
1000
1001 if ($this->num_lines > 0) {
1002 $this->drawLines();
1003 }
1004
1005 if (trim($this->image_signature) != '') {
1006 $this->addSignature();
1007 }
1008
1009 $this->output();
1010 }
1011
1015 protected function allocateColors()
1016 {
1017 // allocate bg color first for imagecreate
1018 $this->gdbgcolor = imagecolorallocate($this->im,
1019 $this->image_bg_color->r,
1020 $this->image_bg_color->g,
1021 $this->image_bg_color->b);
1022
1023 $alpha = intval($this->text_transparency_percentage / 100 * 127);
1024
1025 if ($this->use_transparent_text == true) {
1026 $this->gdtextcolor = imagecolorallocatealpha($this->im,
1027 $this->text_color->r,
1028 $this->text_color->g,
1029 $this->text_color->b,
1030 $alpha);
1031 $this->gdlinecolor = imagecolorallocatealpha($this->im,
1032 $this->line_color->r,
1033 $this->line_color->g,
1034 $this->line_color->b,
1035 $alpha);
1036 $this->gdnoisecolor = imagecolorallocatealpha($this->im,
1037 $this->noise_color->r,
1038 $this->noise_color->g,
1039 $this->noise_color->b,
1040 $alpha);
1041 } else {
1042 $this->gdtextcolor = imagecolorallocate($this->im,
1043 $this->text_color->r,
1044 $this->text_color->g,
1045 $this->text_color->b);
1046 $this->gdlinecolor = imagecolorallocate($this->im,
1047 $this->line_color->r,
1048 $this->line_color->g,
1049 $this->line_color->b);
1050 $this->gdnoisecolor = imagecolorallocate($this->im,
1051 $this->noise_color->r,
1052 $this->noise_color->g,
1053 $this->noise_color->b);
1054 }
1055
1056 $this->gdsignaturecolor = imagecolorallocate($this->im,
1057 $this->signature_color->r,
1058 $this->signature_color->g,
1059 $this->signature_color->b);
1060
1061 }
1062
1066 protected function setBackground()
1067 {
1068 // set background color of image by drawing a rectangle since imagecreatetruecolor doesn't set a bg color
1069 imagefilledrectangle($this->im, 0, 0,
1070 $this->image_width, $this->image_height,
1071 $this->gdbgcolor);
1072 imagefilledrectangle($this->tmpimg, 0, 0,
1073 $this->image_width * $this->iscale, $this->image_height * $this->iscale,
1074 $this->gdbgcolor);
1075
1076 if ($this->bgimg == '') {
1077 if ($this->background_directory != null &&
1078 is_dir($this->background_directory) &&
1079 is_readable($this->background_directory))
1080 {
1082 if ($img != false) {
1083 $this->bgimg = $img;
1084 }
1085 }
1086 }
1087
1088 if ($this->bgimg == '') {
1089 return;
1090 }
1091
1092 $dat = @getimagesize($this->bgimg);
1093 if($dat == false) {
1094 return;
1095 }
1096
1097 switch($dat[2]) {
1098 case 1: $newim = @imagecreatefromgif($this->bgimg); break;
1099 case 2: $newim = @imagecreatefromjpeg($this->bgimg); break;
1100 case 3: $newim = @imagecreatefrompng($this->bgimg); break;
1101 default: return;
1102 }
1103
1104 if(!$newim) return;
1105
1106 imagecopyresized($this->im, $newim, 0, 0, 0, 0,
1107 $this->image_width, $this->image_height,
1108 imagesx($newim), imagesy($newim));
1109 }
1110
1114 protected function getBackgroundFromDirectory()
1115 {
1116 $images = array();
1117
1118 if ( ($dh = opendir($this->background_directory)) !== false) {
1119 while (($file = readdir($dh)) !== false) {
1120 if (preg_match('/(jpg|gif|png)$/i', $file)) $images[] = $file;
1121 }
1122
1123 closedir($dh);
1124
1125 if (sizeof($images) > 0) {
1126 return rtrim($this->background_directory, '/') . '/' . $images[mt_rand(0, sizeof($images)-1)];
1127 }
1128 }
1129
1130 return false;
1131 }
1132
1136 public function createCode()
1137 {
1138 $this->code = false;
1139
1140 switch($this->captcha_type) {
1142 {
1143 do {
1144 $signs = array('+', '-', 'x');
1145 $left = mt_rand(1, 10);
1146 $right = mt_rand(1, 5);
1147 $sign = $signs[mt_rand(0, 2)];
1148
1149 switch($sign) {
1150 case 'x': $c = $left * $right; break;
1151 case '-': $c = $left - $right; break;
1152 default: $c = $left + $right; break;
1153 }
1154 } while ($c <= 0); // no negative #'s or 0
1155
1156 $this->code = $c;
1157 $this->code_display = "$left $sign $right";
1158 break;
1159 }
1160
1162 $words = $this->readCodeFromFile(2);
1163 $this->code = implode(' ', $words);
1164 $this->code_display = $this->code;
1165 break;
1166
1167 default:
1168 {
1169 if ($this->use_wordlist && is_readable($this->wordlist_file)) {
1170 $this->code = $this->readCodeFromFile();
1171 }
1172
1173 if ($this->code == false) {
1174 $this->code = $this->generateCode($this->code_length);
1175 }
1176
1177 $this->code_display = $this->code;
1178 $this->code = ($this->case_sensitive) ? $this->code : strtolower($this->code);
1179 } // default
1180 }
1181
1182 $this->saveData();
1183 }
1184
1188 protected function drawWord()
1189 {
1190 $width2 = $this->image_width * $this->iscale;
1191 $height2 = $this->image_height * $this->iscale;
1192
1193 if (!is_readable($this->ttf_file)) {
1194 imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor);
1195 } else {
1196 if ($this->perturbation > 0) {
1197 $font_size = $height2 * .4;
1198 $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
1199 $tx = $bb[4] - $bb[0];
1200 $ty = $bb[5] - $bb[1];
1201 $x = floor($width2 / 2 - $tx / 2 - $bb[0]);
1202 $y = round($height2 / 2 - $ty / 2 - $bb[1]);
1203
1204 imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
1205 } else {
1206 $font_size = $this->image_height * .4;
1207 $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
1208 $tx = $bb[4] - $bb[0];
1209 $ty = $bb[5] - $bb[1];
1210 $x = floor($this->image_width / 2 - $tx / 2 - $bb[0]);
1211 $y = round($this->image_height / 2 - $ty / 2 - $bb[1]);
1212
1213 imagettftext($this->im, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
1214 }
1215 }
1216
1217 // DEBUG
1218 //$this->im = $this->tmpimg;
1219 //$this->output();
1220
1221 }
1222
1226 protected function distortedCopy()
1227 {
1228 $numpoles = 3; // distortion factor
1229 // make array of poles AKA attractor points
1230 for ($i = 0; $i < $numpoles; ++ $i) {
1231 $px[$i] = mt_rand($this->image_width * 0.2, $this->image_width * 0.8);
1232 $py[$i] = mt_rand($this->image_height * 0.2, $this->image_height * 0.8);
1233 $rad[$i] = mt_rand($this->image_height * 0.2, $this->image_height * 0.8);
1234 $tmp = ((- $this->frand()) * 0.15) - .15;
1235 $amp[$i] = $this->perturbation * $tmp;
1236 }
1237
1238 $bgCol = imagecolorat($this->tmpimg, 0, 0);
1239 $width2 = $this->iscale * $this->image_width;
1240 $height2 = $this->iscale * $this->image_height;
1241 imagepalettecopy($this->im, $this->tmpimg); // copy palette to final image so text colors come across
1242 // loop over $img pixels, take pixels from $tmpimg with distortion field
1243 for ($ix = 0; $ix < $this->image_width; ++ $ix) {
1244 for ($iy = 0; $iy < $this->image_height; ++ $iy) {
1245 $x = $ix;
1246 $y = $iy;
1247 for ($i = 0; $i < $numpoles; ++ $i) {
1248 $dx = $ix - $px[$i];
1249 $dy = $iy - $py[$i];
1250 if ($dx == 0 && $dy == 0) {
1251 continue;
1252 }
1253 $r = sqrt($dx * $dx + $dy * $dy);
1254 if ($r > $rad[$i]) {
1255 continue;
1256 }
1257 $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
1258 $x += $dx * $rscale;
1259 $y += $dy * $rscale;
1260 }
1261 $c = $bgCol;
1262 $x *= $this->iscale;
1263 $y *= $this->iscale;
1264 if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
1265 $c = imagecolorat($this->tmpimg, $x, $y);
1266 }
1267 if ($c != $bgCol) { // only copy pixels of letters to preserve any background image
1268 imagesetpixel($this->im, $ix, $iy, $c);
1269 }
1270 }
1271 }
1272 }
1273
1277 protected function drawLines()
1278 {
1279 for ($line = 0; $line < $this->num_lines; ++ $line) {
1280 $x = $this->image_width * (1 + $line) / ($this->num_lines + 1);
1281 $x += (0.5 - $this->frand()) * $this->image_width / $this->num_lines;
1282 $y = mt_rand($this->image_height * 0.1, $this->image_height * 0.9);
1283
1284 $theta = ($this->frand() - 0.5) * M_PI * 0.7;
1286 $len = mt_rand($w * 0.4, $w * 0.7);
1287 $lwid = mt_rand(0, 2);
1288
1289 $k = $this->frand() * 0.6 + 0.2;
1290 $k = $k * $k * 0.5;
1291 $phi = $this->frand() * 6.28;
1292 $step = 0.5;
1293 $dx = $step * cos($theta);
1294 $dy = $step * sin($theta);
1295 $n = $len / $step;
1296 $amp = 1.5 * $this->frand() / ($k + 5.0 / $len);
1297 $x0 = $x - 0.5 * $len * cos($theta);
1298 $y0 = $y - 0.5 * $len * sin($theta);
1299
1300 $ldx = round(- $dy * $lwid);
1301 $ldy = round($dx * $lwid);
1302
1303 for ($i = 0; $i < $n; ++ $i) {
1304 $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi);
1305 $y = $y0 + $i * $dy - $amp * $dx * sin($k * $i * $step + $phi);
1306 imagefilledrectangle($this->im, $x, $y, $x + $lwid, $y + $lwid, $this->gdlinecolor);
1307 }
1308 }
1309 }
1310
1314 protected function drawNoise()
1315 {
1316 if ($this->noise_level > 10) {
1317 $noise_level = 10;
1318 } else {
1320 }
1321
1322 $t0 = microtime(true);
1323
1324 $noise_level *= 125; // an arbitrary number that works well on a 1-10 scale
1325
1326 $points = $this->image_width * $this->image_height * $this->iscale;
1327 $height = $this->image_height * $this->iscale;
1328 $width = $this->image_width * $this->iscale;
1329 for ($i = 0; $i < $noise_level; ++$i) {
1330 $x = mt_rand(10, $width);
1331 $y = mt_rand(10, $height);
1332 $size = mt_rand(7, 10);
1333 if ($x - $size <= 0 && $y - $size <= 0) continue; // dont cover 0,0 since it is used by imagedistortedcopy
1334 imagefilledarc($this->tmpimg, $x, $y, $size, $size, 0, 360, $this->gdnoisecolor, IMG_ARC_PIE);
1335 }
1336
1337 $t1 = microtime(true);
1338
1339 $t = $t1 - $t0;
1340
1341 /*
1342 // DEBUG
1343 imagestring($this->tmpimg, 5, 25, 30, "$t", $this->gdnoisecolor);
1344 header('content-type: image/png');
1345 imagepng($this->tmpimg);
1346 exit;
1347 */
1348 }
1349
1353 protected function addSignature()
1354 {
1355 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature);
1356 $textlen = $bbox[2] - $bbox[0];
1357 $x = $this->image_width - $textlen - 5;
1358 $y = $this->image_height - 3;
1359
1360 imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature);
1361 }
1362
1366 protected function output()
1367 {
1368 if ($this->canSendHeaders() || $this->send_headers == false) {
1369 if ($this->send_headers) {
1370 // only send the content-type headers if no headers have been output
1371 // this will ease debugging on misconfigured servers where warnings
1372 // may have been output which break the image and prevent easily viewing
1373 // source to see the error.
1374 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
1375 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT");
1376 header("Cache-Control: no-store, no-cache, must-revalidate");
1377 header("Cache-Control: post-check=0, pre-check=0", false);
1378 header("Pragma: no-cache");
1379 }
1380
1381 switch ($this->image_type) {
1383 if ($this->send_headers) header("Content-Type: image/jpeg");
1384 imagejpeg($this->im, null, 90);
1385 break;
1386 case self::SI_IMAGE_GIF:
1387 if ($this->send_headers) header("Content-Type: image/gif");
1388 imagegif($this->im);
1389 break;
1390 default:
1391 if ($this->send_headers) header("Content-Type: image/png");
1392 imagepng($this->im);
1393 break;
1394 }
1395 } else {
1396 echo '<hr /><strong>'
1397 .'Failed to generate captcha image, content has already been '
1398 .'output.<br />This is most likely due to misconfiguration or '
1399 .'a PHP error was sent to the browser.</strong>';
1400 }
1401
1402 imagedestroy($this->im);
1403 restore_error_handler();
1404
1405 if (!$this->no_exit) exit;
1406 }
1407
1413 protected function getAudibleCode()
1414 {
1415 $letters = array();
1416 $code = $this->getCode(true, true);
1417
1418 if ($code['code'] == '') {
1419 if (strlen($this->display_value) > 0) {
1420 $code = array('code' => $this->display_value, 'display' => $this->display_value);
1421 } else {
1422 $this->createCode();
1423 $code = $this->getCode(true);
1424 }
1425 }
1426
1427 if (preg_match('/(\d+) (\+|-|x) (\d+)/i', $code['display'], $eq)) {
1428 $math = true;
1429
1430 $left = $eq[1];
1431 $sign = str_replace(array('+', '-', 'x'), array('plus', 'minus', 'times'), $eq[2]);
1432 $right = $eq[3];
1433
1434 $letters = array($left, $sign, $right);
1435 } else {
1436 $math = false;
1437
1438 $length = strlen($code['display']);
1439
1440 for($i = 0; $i < $length; ++$i) {
1441 $letter = $code['display']{$i};
1442 $letters[] = $letter;
1443 }
1444 }
1445
1446 try {
1447 return $this->generateWAV($letters);
1448 } catch(Exception $ex) {
1449 throw $ex;
1450 }
1451 }
1452
1456 protected function readCodeFromFile($numWords = 1)
1457 {
1458 $fp = fopen($this->wordlist_file, 'rb');
1459 if (!$fp) return false;
1460
1461 $fsize = filesize($this->wordlist_file);
1462 if ($fsize < 128) return false; // too small of a list to be effective
1463
1464 if ((int)$numWords < 1 || (int)$numWords > 5) $numWords = 1;
1465
1466 $words = array();
1467 $i = 0;
1468 do {
1469 fseek($fp, mt_rand(0, $fsize - 64), SEEK_SET); // seek to a random position of file from 0 to filesize-64
1470 $data = fread($fp, 64); // read a chunk from our random position
1471 $data = preg_replace("/\r?\n/", "\n", $data);
1472
1473 $start = @strpos($data, "\n", mt_rand(0, 56)) + 1; // random start position
1474 $end = @strpos($data, "\n", $start); // find end of word
1475
1476 if ($start === false) {
1477 // picked start position at end of file
1478 continue;
1479 } else if ($end === false) {
1480 $end = strlen($data);
1481 }
1482
1483 $word = strtolower(substr($data, $start, $end - $start)); // return a line of the file
1484 $words[] = $word;
1485 } while (++$i < $numWords);
1486
1487 fclose($fp);
1488
1489 if ($numWords < 2) {
1490 return $words[0];
1491 } else {
1492 return $words;
1493 }
1494 }
1495
1499 protected function generateCode()
1500 {
1501 $code = '';
1502
1503 if (function_exists('mb_strlen')) {
1504 for($i = 1, $cslen = mb_strlen($this->charset); $i <= $this->code_length; ++$i) {
1505 $code .= mb_substr($this->charset, mt_rand(0, $cslen - 1), 1, 'UTF-8');
1506 }
1507 } else {
1508 for($i = 1, $cslen = strlen($this->charset); $i <= $this->code_length; ++$i) {
1509 $code .= substr($this->charset, mt_rand(0, $cslen - 1), 1);
1510 }
1511 }
1512
1513 return $code;
1514 }
1515
1520 protected function validate()
1521 {
1522 if (!is_string($this->code) || strlen($this->code) == 0) {
1523 $code = $this->getCode();
1524 // returns stored code, or an empty string if no stored code was found
1525 // checks the session and database if enabled
1526 } else {
1528 }
1529
1530 if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) {
1531 // case sensitive was set from securimage_show.php but not in class
1532 // the code saved in the session has capitals so set case sensitive to true
1533 $this->case_sensitive = true;
1534 }
1535
1536 $code_entered = trim( (($this->case_sensitive) ? $this->code_entered
1537 : strtolower($this->code_entered))
1538 );
1539 $this->correct_code = false;
1540
1541 if ($code != '') {
1542 if (strpos($code, ' ') !== false) {
1543 // for multi word captchas, remove more than once space from input
1544 $code_entered = preg_replace('/\s+/', ' ', $code_entered);
1545 $code_entered = strtolower($code_entered);
1546 }
1547
1548 if ($code == $code_entered) {
1549 $this->correct_code = true;
1550 if ($this->no_session != true) {
1551 $_SESSION['securimage_code_value'][$this->namespace] = '';
1552 $_SESSION['securimage_code_ctime'][$this->namespace] = '';
1553 }
1554 $this->clearCodeFromDatabase();
1555 }
1556 }
1557 }
1558
1562 protected function saveData()
1563 {
1564 if ($this->no_session != true) {
1565 if (isset($_SESSION['securimage_code_value']) && is_scalar($_SESSION['securimage_code_value'])) {
1566 // fix for migration from v2 - v3
1567 unset($_SESSION['securimage_code_value']);
1568 unset($_SESSION['securimage_code_ctime']);
1569 }
1570
1571 $_SESSION['securimage_code_disp'] [$this->namespace] = $this->code_display;
1572 $_SESSION['securimage_code_value'][$this->namespace] = $this->code;
1573 $_SESSION['securimage_code_ctime'][$this->namespace] = time();
1574 }
1575
1576 if ($this->use_database) {
1577 $this->saveCodeToDatabase();
1578 }
1579 }
1580
1584 protected function saveCodeToDatabase()
1585 {
1586 $success = false;
1587 $this->openDatabase();
1588
1589 if ($this->use_database && $this->pdo_conn) {
1590 $id = $this->getCaptchaId(false);
1591 $ip = $_SERVER['REMOTE_ADDR'];
1592
1593 if (empty($id)) {
1594 $id = $ip;
1595 }
1596
1597 $time = time();
1599 $code_disp = $this->code_display;
1600
1601 // This is somewhat expensive in PDO Sqlite3 (when there is something to delete)
1602 $this->clearCodeFromDatabase();
1603
1604 $query = "INSERT INTO {$this->database_table} ("
1605 ."id, code, code_display, namespace, created) "
1606 ."VALUES(?, ?, ?, ?, ?)";
1607
1608 $stmt = $this->pdo_conn->prepare($query);
1609 $success = $stmt->execute(array($id, $code, $code_disp, $this->namespace, $time));
1610
1611 if (!$success) {
1612 $err = $stmt->errorInfo();
1613 trigger_error("Failed to insert code into database. {$err[1]}: {$err[2]}", E_USER_WARNING);
1614 }
1615 }
1616
1617 return $success !== false;
1618 }
1619
1623 protected function openDatabase()
1624 {
1625 $this->pdo_conn = false;
1626
1627 if ($this->use_database) {
1628 $pdo_extension = 'PDO_' . strtoupper($this->database_driver);
1629
1630 if (!extension_loaded($pdo_extension)) {
1631 trigger_error("Database support is turned on in Securimage, but the chosen extension $pdo_extension is not loaded in PHP.", E_USER_WARNING);
1632 return false;
1633 }
1634 }
1635
1636 if ($this->database_driver == self::SI_DRIVER_SQLITE3) {
1637 if (!file_exists($this->database_file)) {
1638 $fp = fopen($this->database_file, 'w+');
1639 if (!$fp) {
1640 $err = error_get_last();
1641 trigger_error("Securimage failed to create SQLite3 database file '{$this->database_file}'. Reason: {$err['message']}", E_USER_WARNING);
1642 return false;
1643 }
1644 fclose($fp);
1645 chmod($this->database_file, 0666);
1646 } else if (!is_writeable($this->database_file)) {
1647 trigger_error("Securimage does not have read/write access to database file '{$this->database_file}. Make sure permissions are 0666 and writeable by user '" . get_current_user() . "'", E_USER_WARNING);
1648 return false;
1649 }
1650 }
1651
1652 $dsn = $this->getDsn();
1653
1654 try {
1655 $options = array();
1656 $this->pdo_conn = new PDO($dsn, $this->database_user, $this->database_pass, $options);
1657 } catch (PDOException $pdoex) {
1658 trigger_error("Database connection failed: " . $pdoex->getMessage(), E_USER_WARNING);
1659 return false;
1660 }
1661
1662 try {
1663 if (!$this->checkTablesExist()) {
1664 // create tables...
1665 $this->createDatabaseTables();
1666 }
1667 } catch (Exception $ex) {
1668 trigger_error($ex->getMessage(), E_USER_WARNING);
1669 $this->pdo_conn = null;
1670 return false;
1671 }
1672
1673 if (mt_rand(0, 100) / 100.0 == 1.0) {
1675 }
1676
1677 return $this->pdo_conn;
1678 }
1679
1680 protected function getDsn()
1681 {
1682 $dsn = sprintf('%s:', $this->database_driver);
1683
1684 switch($this->database_driver) {
1686 $dsn .= $this->database_file;
1687 break;
1688
1691 $dsn .= sprintf('host=%s;dbname=%s',
1692 $this->database_host,
1693 $this->database_name);
1694 break;
1695
1696 }
1697
1698 return $dsn;
1699 }
1700
1701 protected function checkTablesExist()
1702 {
1703 $table = $this->pdo_conn->quote($this->database_table);
1704
1705 switch($this->database_driver) {
1707 // query row count for sqlite, PRAGMA queries seem to return no
1708 // rowCount using PDO even if there are rows returned
1709 $query = "SELECT COUNT(id) FROM $table";
1710 break;
1711
1713 $query = "SHOW TABLES LIKE $table";
1714 break;
1715
1717 $query = "SELECT * FROM information_schema.columns WHERE table_name = $table;";
1718 break;
1719 }
1720
1721 $result = $this->pdo_conn->query($query);
1722
1723 if (!$result) {
1724 $err = $this->pdo_conn->errorInfo();
1725
1726 if ($this->database_driver == self::SI_DRIVER_SQLITE3 &&
1727 $err[1] === 1 && strpos($err[2], 'no such table') !== false)
1728 {
1729 return false;
1730 }
1731
1732 throw new Exception("Failed to check tables: {$err[0]} - {$err[1]}: {$err[2]}");
1733 } else if ($this->database_driver == self::SI_DRIVER_SQLITE3) {
1734 // successful here regardless of row count for sqlite
1735 return true;
1736 } else if ($result->rowCount() == 0) {
1737 return false;
1738 } else {
1739 return true;
1740 }
1741 }
1742
1743 protected function createDatabaseTables()
1744 {
1745 $queries = array();
1746
1747 switch($this->database_driver) {
1749 $queries[] = "CREATE TABLE \"{$this->database_table}\" (
1750 id VARCHAR(40),
1751 namespace VARCHAR(32) NOT NULL,
1752 code VARCHAR(32) NOT NULL,
1753 code_display VARCHAR(32) NOT NULL,
1754 created INTEGER NOT NULL,
1755 PRIMARY KEY(id, namespace)
1756 )";
1757
1758 $queries[] = "CREATE INDEX ndx_created ON {$this->database_table} (created)";
1759 break;
1760
1762 $queries[] = "CREATE TABLE `{$this->database_table}` (
1763 `id` VARCHAR(40) NOT NULL,
1764 `namespace` VARCHAR(32) NOT NULL,
1765 `code` VARCHAR(32) NOT NULL,
1766 `code_display` VARCHAR(32) NOT NULL,
1767 `created` INT NOT NULL,
1768 PRIMARY KEY(id, namespace),
1769 INDEX(created)
1770 )";
1771 break;
1772
1774 $queries[] = "CREATE TABLE {$this->database_table} (
1775 id character varying(40) NOT NULL,
1776 namespace character varying(32) NOT NULL,
1777 code character varying(32) NOT NULL,
1778 code_display character varying(32) NOT NULL,
1779 created integer NOT NULL,
1780 CONSTRAINT pkey_id_namespace PRIMARY KEY (id, namespace)
1781 )";
1782
1783 $queries[] = "CREATE INDEX ndx_created ON {$this->database_table} (created);";
1784 break;
1785 }
1786
1787 $this->pdo_conn->beginTransaction();
1788
1789 foreach($queries as $query) {
1790 $result = $this->pdo_conn->query($query);
1791
1792 if (!$result) {
1793 $err = $this->pdo_conn->errorInfo();
1794 trigger_error("Failed to create table. {$err[1]}: {$err[2]}", E_USER_WARNING);
1795 $this->pdo_conn->rollBack();
1796 $this->pdo_conn = false;
1797 return false;
1798 }
1799 }
1800
1801 $this->pdo_conn->commit();
1802
1803 return true;
1804 }
1805
1813 protected function getCodeFromDatabase()
1814 {
1815 $code = '';
1816
1817 if ($this->use_database == true && $this->pdo_conn) {
1818 if (Securimage::$_captchaId !== null) {
1819 $query = "SELECT * FROM {$this->database_table} WHERE id = ?";
1820 $stmt = $this->pdo_conn->prepare($query);
1821 $result = $stmt->execute(array(Securimage::$_captchaId));
1822 } else {
1823 $ip = $_SERVER['REMOTE_ADDR'];
1824 $ns = $this->namespace;
1825
1826 // ip is stored in id column when no captchaId
1827 $query = "SELECT * FROM {$this->database_table} WHERE id = ? AND namespace = ?";
1828 $stmt = $this->pdo_conn->prepare($query);
1829 $result = $stmt->execute(array($ip, $ns));
1830 }
1831
1832 if (!$result) {
1833 $err = $this->pdo_conn->errorInfo();
1834 trigger_error("Failed to select code from database. {$err[0]}: {$err[1]}", E_USER_WARNING);
1835 } else {
1836 if ( ($row = $stmt->fetch()) !== false ) {
1837 if (false == $this->isCodeExpired($row['created'])) {
1838 if (Securimage::$_captchaId !== null) {
1839 // return an array when using captchaId
1840 $code = array('code' => $row['code'],
1841 'code_disp' => $row['code_display']);
1842 } else {
1843 $code = $row['code'];
1844 }
1845 }
1846 }
1847 }
1848 }
1849
1850 return $code;
1851 }
1852
1856 protected function clearCodeFromDatabase()
1857 {
1858 if ($this->pdo_conn) {
1859 $ip = $_SERVER['REMOTE_ADDR'];
1860 $ns = $this->pdo_conn->quote($this->namespace);
1862
1863 if (empty($id)) {
1864 $id = $ip; // if no captchaId set, IP address is captchaId.
1865 }
1866
1867 $id = $this->pdo_conn->quote($id);
1868
1869 $query = sprintf("DELETE FROM %s WHERE id = %s AND namespace = %s",
1870 $this->database_table, $id, $ns);
1871
1872 $result = $this->pdo_conn->query($query);
1873 if (!$result) {
1874 trigger_error("Failed to delete code from database.", E_USER_WARNING);
1875 }
1876 }
1877 }
1878
1882 protected function purgeOldCodesFromDatabase()
1883 {
1884 if ($this->use_database && $this->pdo_conn) {
1885 $now = time();
1886 $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
1887
1888 $query = sprintf("DELETE FROM %s WHERE %s - created > %s",
1889 $this->database_table,
1890 $this->pdo_conn->quote($now, PDO::PARAM_INT),
1891 $this->pdo_conn->quote($limit, PDO::PARAM_INT));
1892
1893 $result = $this->pdo_conn->query($query);
1894 }
1895 }
1896
1901 protected function isCodeExpired($creation_time)
1902 {
1903 $expired = true;
1904
1905 if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
1906 $expired = false;
1907 } else if (time() - $creation_time < $this->expiry_time) {
1908 $expired = false;
1909 }
1910
1911 return $expired;
1912 }
1913
1920 protected function generateWAV($letters)
1921 {
1922 $wavCaptcha = new WavFile();
1923 $first = true; // reading first wav file
1924
1925 foreach ($letters as $letter) {
1926 $letter = strtoupper($letter);
1927
1928 try {
1929 $l = new WavFile($this->audio_path . '/' . $letter . '.wav');
1930
1931 if ($first) {
1932 // set sample rate, bits/sample, and # of channels for file based on first letter
1933 $wavCaptcha->setSampleRate($l->getSampleRate())
1934 ->setBitsPerSample($l->getBitsPerSample())
1935 ->setNumChannels($l->getNumChannels());
1936 $first = false;
1937 }
1938
1939 // append letter to the captcha audio
1940 $wavCaptcha->appendWav($l);
1941
1942 // random length of silence between $audio_gap_min and $audio_gap_max
1943 if ($this->audio_gap_max > 0 && $this->audio_gap_max > $this->audio_gap_min) {
1944 $wavCaptcha->insertSilence( mt_rand($this->audio_gap_min, $this->audio_gap_max) / 1000.0 );
1945 }
1946 } catch (Exception $ex) {
1947 // failed to open file, or the wav file is broken or not supported
1948 // 2 wav files were not compatible, different # channels, bits/sample, or sample rate
1949 throw $ex;
1950 }
1951 }
1952
1953 /********* Set up audio filters *****************************/
1954 $filters = array();
1955
1956 if ($this->audio_use_noise == true) {
1957 // use background audio - find random file
1958 $noiseFile = $this->getRandomNoiseFile();
1959
1960 if ($noiseFile !== false && is_readable($noiseFile)) {
1961 try {
1962 $wavNoise = new WavFile($noiseFile, false);
1963 } catch(Exception $ex) {
1964 throw $ex;
1965 }
1966
1967 // start at a random offset from the beginning of the wavfile
1968 // in order to add more randomness
1969 $randOffset = 0;
1970 if ($wavNoise->getNumBlocks() > 2 * $wavCaptcha->getNumBlocks()) {
1971 $randBlock = mt_rand(0, $wavNoise->getNumBlocks() - $wavCaptcha->getNumBlocks());
1972 $wavNoise->readWavData($randBlock * $wavNoise->getBlockAlign(), $wavCaptcha->getNumBlocks() * $wavNoise->getBlockAlign());
1973 } else {
1974 $wavNoise->readWavData();
1975 $randOffset = mt_rand(0, $wavNoise->getNumBlocks() - 1);
1976 }
1977
1978
1979 $mixOpts = array('wav' => $wavNoise,
1980 'loop' => true,
1981 'blockOffset' => $randOffset);
1982
1983 $filters[WavFile::FILTER_MIX] = $mixOpts;
1985 }
1986 }
1987
1988 if ($this->degrade_audio == true) {
1989 // add random noise.
1990 // any noise level below 95% is intensely distorted and not pleasant to the ear
1991 $filters[WavFile::FILTER_DEGRADE] = mt_rand(95, 98) / 100.0;
1992 }
1993
1994 if (!empty($filters)) {
1995 $wavCaptcha->filter($filters); // apply filters to captcha audio
1996 }
1997
1998 return $wavCaptcha->__toString();
1999 }
2000
2001 public function getRandomNoiseFile()
2002 {
2003 $return = false;
2004
2005 if ( ($dh = opendir($this->audio_noise_path)) !== false ) {
2006 $list = array();
2007
2008 while ( ($file = readdir($dh)) !== false ) {
2009 if ($file == '.' || $file == '..') continue;
2010 if (strtolower(substr($file, -4)) != '.wav') continue;
2011
2012 $list[] = $file;
2013 }
2014
2015 closedir($dh);
2016
2017 if (sizeof($list) > 0) {
2018 $file = $list[array_rand($list, 1)];
2019 $return = $this->audio_noise_path . DIRECTORY_SEPARATOR . $file;
2020 }
2021 }
2022
2023 return $return;
2024 }
2025
2031 protected function audioError()
2032 {
2033 return @file_get_contents(dirname(__FILE__) . '/audio/en/error.wav');
2034 }
2035
2041 protected function canSendHeaders()
2042 {
2043 if (headers_sent()) {
2044 // output has been flushed and headers have already been sent
2045 return false;
2046 } else if (strlen((string)ob_get_contents()) > 0) {
2047 // headers haven't been sent, but there is data in the buffer that will break image and audio data
2048 return false;
2049 }
2050
2051 return true;
2052 }
2053
2059 function frand()
2060 {
2061 return 0.0001 * mt_rand(0,9999);
2062 }
2063
2069 protected function initColor($color, $default)
2070 {
2071 if ($color == null) {
2072 return new Securimage_Color($default);
2073 } else if (is_string($color)) {
2074 try {
2075 return new Securimage_Color($color);
2076 } catch(Exception $e) {
2077 return new Securimage_Color($default);
2078 }
2079 } else if (is_array($color) && sizeof($color) == 3) {
2080 return new Securimage_Color($color[0], $color[1], $color[2]);
2081 } else {
2082 return new Securimage_Color($default);
2083 }
2084 }
2085
2101 public function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array())
2102 {
2103 // get the current error reporting level
2104 $level = error_reporting();
2105
2106 // if error was supressed or $errno not set in current error level
2107 if ($level == 0 || ($level & $errno) == 0) {
2108 return true;
2109 }
2110
2111 return false;
2112 }
2113}
2114
2115
2126{
2127 public $r;
2128 public $g;
2129 public $b;
2130
2142 public function __construct($color = '#ffffff')
2143 {
2144 $args = func_get_args();
2145
2146 if (sizeof($args) == 0) {
2147 $this->r = 255;
2148 $this->g = 255;
2149 $this->b = 255;
2150 } else if (sizeof($args) == 1) {
2151 // set based on html code
2152 if (substr($color, 0, 1) == '#') {
2153 $color = substr($color, 1);
2154 }
2155
2156 if (strlen($color) != 3 && strlen($color) != 6) {
2157 throw new InvalidArgumentException(
2158 'Invalid HTML color code passed to Securimage_Color'
2159 );
2160 }
2161
2162 $this->constructHTML($color);
2163 } else if (sizeof($args) == 3) {
2164 $this->constructRGB($args[0], $args[1], $args[2]);
2165 } else {
2166 throw new InvalidArgumentException(
2167 'Securimage_Color constructor expects 0, 1 or 3 arguments; ' . sizeof($args) . ' given'
2168 );
2169 }
2170 }
2171
2178 protected function constructRGB($red, $green, $blue)
2179 {
2180 if ($red < 0) $red = 0;
2181 if ($red > 255) $red = 255;
2182 if ($green < 0) $green = 0;
2183 if ($green > 255) $green = 255;
2184 if ($blue < 0) $blue = 0;
2185 if ($blue > 255) $blue = 255;
2186
2187 $this->r = $red;
2188 $this->g = $green;
2189 $this->b = $blue;
2190 }
2191
2196 protected function constructHTML($color)
2197 {
2198 if (strlen($color) == 3) {
2199 $red = str_repeat(substr($color, 0, 1), 2);
2200 $green = str_repeat(substr($color, 1, 1), 2);
2201 $blue = str_repeat(substr($color, 2, 1), 2);
2202 } else {
2203 $red = substr($color, 0, 2);
2204 $green = substr($color, 2, 2);
2205 $blue = substr($color, 4, 2);
2206 }
2207
2208 $this->r = hexdec($red);
2209 $this->g = hexdec($green);
2210 $this->b = hexdec($blue);
2211 }
2212}
$result
print $file
$n
Definition: RandomTest.php:80
$size
Definition: RandomTest.php:79
$success
Definition: Utf8Test.php:87
global $l
Definition: afr.php:30
$_SESSION["AccountId"]
__construct($color='#ffffff')
Create a new Securimage_Color object.
constructRGB($red, $green, $blue)
Construct from an rgb triplet.
constructHTML($color)
Construct from an html hex color code.
errorHandler($errno, $errstr, $errfile='', $errline=0, $errcontext=array())
Error handler used when outputting captcha image or audio.
const SI_CAPTCHA_STRING
Definition: securimage.php:191
const SI_DRIVER_MYSQL
Definition: securimage.php:208
validate()
Checks the entered code against the value stored in the session or sqlite database,...
getCode($array=false, $returnExisting=false)
Return the code from the session or sqlite database if used.
Definition: securimage.php:899
check($code)
Check a submitted code against the stored value.
Definition: securimage.php:831
const SI_DRIVER_SQLITE3
Definition: securimage.php:222
saveData()
Save data to session namespace and database if used.
drawLines()
Draws distorted lines on the image.
static getCaptchaId($new=true, array $options=array())
Generate a new captcha ID or retrieve the current ID.
Definition: securimage.php:735
isCodeExpired($creation_time)
Checks to see if the captcha code has expired and cannot be used.
$audio_mix_normalization
Definition: securimage.php:511
saveCodeToDatabase()
Saves the code to the sqlite database.
output()
Sends the appropriate image and cache headers and outputs image to the browser.
getRandomNoiseFile()
allocateColors()
Allocate the colors to be used for the image.
show($background_image='')
Used to serve a captcha image to the browser.
Definition: securimage.php:807
__construct($options=array())
Create a new securimage object, pass options to set in the constructor.
Definition: securimage.php:629
purgeOldCodesFromDatabase()
Deletes old codes from sqlite database.
static getPath()
Return the absolute path to the Securimage directory.
Definition: securimage.php:721
audioError()
Return a wav file saying there was an error generating file.
outputAudioFile()
Output a wav file of the captcha code to the browser.
Definition: securimage.php:847
$text_transparency_percentage
Definition: securimage.php:268
initColor($color, $default)
Convert an html color code to a Securimage_Color.
const SI_DRIVER_PGSQL
Definition: securimage.php:215
drawWord()
Draws the captcha code on the image.
const SI_IMAGE_JPEG
Definition: securimage.php:175
getCodeFromDatabase()
Get a code from the sqlite database for ip address/captchaId.
createCode()
Generates the code or math problem and saves the value to the session.
clearCodeFromDatabase()
Remove an entered code from the database.
openDatabase()
Open sqlite database.
getAudibleCode()
Gets the code and returns the binary audio file for the stored captcha code.
const SI_IMAGE_GIF
Definition: securimage.php:185
doImage()
The main image drawing routing, responsible for constructing the entire image and serving it.
Definition: securimage.php:944
createDatabaseTables()
distortedCopy()
Copies the captcha image to the final image with distortion applied.
setBackground()
The the background color, or background image to be used.
static $_captchaId
Definition: securimage.php:539
static checkByCaptchaId($id, $value, array $options=array())
Validate a captcha code input against a captcha ID.
Definition: securimage.php:763
getBackgroundFromDirectory()
Scan the directory for a background image to use.
generateWAV($letters)
Generate a wav file given the $letters in the code.
canSendHeaders()
Checks to see if headers can be sent and if any error has been output to the browser.
const SI_CAPTCHA_WORDS
Definition: securimage.php:201
const SI_CAPTCHA_MATHEMATIC
Definition: securimage.php:196
generateCode()
Generates a random captcha code from the set character set.
addSignature()
Print signature text on image.
frand()
Return a random float between 0 and 0.9999.
drawNoise()
Draws random noise on the image.
readCodeFromFile($numWords=1)
Gets a captcha code from a wordlist.
const SI_IMAGE_PNG
Definition: securimage.php:180
const FILTER_DEGRADE
Definition: WavFile.php:81
const FILTER_MIX
Definition: WavFile.php:75
const FILTER_NORMALIZE
Definition: WavFile.php:78
$y
Definition: example_007.php:83
$x
Definition: example_009.php:98
$w
$data
$px
$py
$red
Definition: example_030.php:80
$green
Definition: example_030.php:83
$blue
Definition: example_030.php:81
$r
Definition: example_031.php:79
exit
Definition: login.php:54
Project: Securimage: A PHP class for creating and managing form CAPTCHA images File: securimage....
if(!is_array($argv)) $options
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']