217 public $charset =
'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
366 $this->securimage_path = dirname(__FILE__);
368 if (is_array($options) &&
sizeof($options) > 0) {
369 foreach($options as $prop => $val) {
380 if ($this->ttf_file == null) {
381 $this->ttf_file = $this->securimage_path .
'/AHGBold.ttf';
386 if ($this->wordlist_file == null) {
387 $this->wordlist_file = $this->securimage_path .
'/words/words.txt';
390 if ($this->sqlite_database == null) {
391 $this->sqlite_database = $this->securimage_path .
'/database/securimage.sqlite';
394 if ($this->audio_path == null) {
395 $this->audio_path = $this->securimage_path .
'/audio/';
406 if ($this->
namespace == null || !is_string($this->
namespace)) {
407 $this->
namespace = 'default';
411 if ( session_id() ==
'' ) {
412 if ($this->session_name != null && trim($this->session_name) !=
'') {
413 session_name(trim($this->session_name));
425 return dirname(__FILE__);
441 public function show($background_image =
'')
443 if($background_image !=
'' && is_readable($background_image)) {
444 $this->bgimg = $background_image;
465 $this->code_entered =
$code;
467 return $this->correct_code;
483 header(
"Content-Disposition: attachment; filename=\"securimage_audio.{$ext}\"");
484 header(
'Cache-Control: no-store, no-cache, must-revalidate');
485 header(
'Expires: Sun, 1 Jan 2000 12:00:00 GMT');
486 header(
'Last-Modified: ' . gmdate(
'D, d M Y H:i:s') .
'GMT');
487 header(
'Content-type: audio/x-wav');
491 header(
'Content-Length: ' . strlen($audio));
502 if( ($this->
use_transparent_text ==
true || $this->bgimg !=
'') && function_exists(
'imagecreatetruecolor')) {
503 $imagecreate =
'imagecreatetruecolor';
505 $imagecreate =
'imagecreate';
512 imagepalettecopy($this->tmpimg, $this->im);
524 if ($this->
perturbation > 0 && is_readable($this->ttf_file)) {
545 $this->gdbgcolor = imagecolorallocate($this->im,
547 $this->image_bg_color->g,
548 $this->image_bg_color->b);
553 $this->gdtextcolor = imagecolorallocatealpha($this->im,
555 $this->text_color->g,
556 $this->text_color->b,
558 $this->gdlinecolor = imagecolorallocatealpha($this->im,
560 $this->line_color->g,
561 $this->line_color->b,
563 $this->gdnoisecolor = imagecolorallocatealpha($this->im,
565 $this->noise_color->g,
566 $this->noise_color->b,
569 $this->gdtextcolor = imagecolorallocate($this->im,
571 $this->text_color->g,
572 $this->text_color->b);
573 $this->gdlinecolor = imagecolorallocate($this->im,
575 $this->line_color->g,
576 $this->line_color->b);
577 $this->gdnoisecolor = imagecolorallocate($this->im,
579 $this->noise_color->g,
580 $this->noise_color->b);
583 $this->gdsignaturecolor = imagecolorallocate($this->im,
585 $this->signature_color->g,
586 $this->signature_color->b);
596 imagefilledrectangle($this->im, 0, 0,
599 imagefilledrectangle($this->tmpimg, 0, 0,
603 if ($this->bgimg ==
'') {
604 if ($this->background_directory != null &&
605 is_dir($this->background_directory) &&
606 is_readable($this->background_directory))
615 if ($this->bgimg ==
'') {
619 $dat = @getimagesize($this->bgimg);
625 case 1: $newim = @imagecreatefromgif($this->bgimg);
break;
626 case 2: $newim = @imagecreatefromjpeg($this->bgimg);
break;
627 case 3: $newim = @imagecreatefrompng($this->bgimg);
break;
633 imagecopyresized($this->im, $newim, 0, 0, 0, 0,
635 imagesx($newim), imagesy($newim));
645 if ( ($dh = opendir($this->background_directory)) !==
false) {
646 while ((
$file = readdir($dh)) !==
false) {
647 if (preg_match(
'/(jpg|gif|png)$/i',
$file)) $images[] =
$file;
652 if (
sizeof($images) > 0) {
653 return rtrim($this->background_directory,
'/') .
'/' . $images[rand(0,
sizeof($images)-1)];
667 switch($this->captcha_type) {
668 case self::SI_CAPTCHA_MATHEMATIC:
670 $signs = array(
'+',
'-',
'x');
673 $sign = $signs[rand(0, 2)];
676 case 'x': $c = $left * $right;
break;
677 case '-': $c = $left - $right;
break;
678 default: $c = $left + $right;
break;
682 $this->code_display =
"$left $sign $right";
688 if ($this->
use_wordlist && is_readable($this->wordlist_file)) {
692 if ($this->code ==
false) {
712 if (!is_readable($this->ttf_file)) {
713 imagestring($this->im, 4, 10, ($this->
image_height / 2) - 5,
'Failed to load TTF font file!', $this->gdtextcolor);
716 $font_size = $height2 * .4;
717 $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
718 $tx = $bb[4] - $bb[0];
719 $ty = $bb[5] - $bb[1];
720 $x = floor($width2 / 2 - $tx / 2 - $bb[0]);
721 $y = round($height2 / 2 - $ty / 2 - $bb[1]);
723 imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
726 $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
727 $tx = $bb[4] - $bb[0];
728 $ty = $bb[5] - $bb[1];
729 $x = floor($this->
image_width / 2 - $tx / 2 - $bb[0]);
732 imagettftext($this->im, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
749 for ($i = 0; $i < $numpoles; ++ $i) {
753 $tmp = ((- $this->
frand()) * 0.15) - .15;
757 $bgCol = imagecolorat($this->tmpimg, 0, 0);
760 imagepalettecopy($this->im, $this->tmpimg);
766 for ($i = 0; $i < $numpoles; ++ $i) {
769 if ($dx == 0 && $dy == 0) {
772 $r = sqrt($dx * $dx + $dy * $dy);
776 $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
783 if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
784 $c = imagecolorat($this->tmpimg, $x, $y);
787 imagesetpixel($this->im, $ix, $iy, $c);
799 $x = $this->
image_width * (1 + $line) / ($this->num_lines + 1);
803 $theta = ($this->
frand() - 0.5) * M_PI * 0.7;
805 $len = rand($w * 0.4, $w * 0.7);
808 $k = $this->
frand() * 0.6 + 0.2;
810 $phi = $this->
frand() * 6.28;
812 $dx = $step * cos($theta);
813 $dy = $step * sin($theta);
815 $amp = 1.5 * $this->
frand() / ($k + 5.0 / $len);
816 $x0 = $x - 0.5 * $len * cos($theta);
817 $y0 = $y - 0.5 * $len * sin($theta);
819 $ldx = round(- $dy * $lwid);
820 $ldy = round($dx * $lwid);
822 for ($i = 0; $i <
$n; ++ $i) {
823 $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi);
824 $y = $y0 + $i * $dy - $amp * $dx * sin($k * $i * $step + $phi);
825 imagefilledrectangle($this->im, $x, $y, $x + $lwid, $y + $lwid, $this->gdlinecolor);
841 $t0 = microtime(
true);
849 $x = rand(10, $width);
850 $y = rand(10, $height);
852 if ($x -
$size <= 0 && $y -
$size <= 0)
continue;
853 imagefilledarc($this->tmpimg, $x, $y,
$size,
$size, 0, 360, $this->gdnoisecolor, IMG_ARC_PIE);
856 $t1 = microtime(
true);
874 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->
image_signature);
875 $textlen = $bbox[2] - $bbox[0];
879 imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->
image_signature);
887 header(
"Expires: Mon, 26 Jul 1997 05:00:00 GMT");
888 header(
"Last-Modified: " . gmdate(
"D, d M Y H:i:s") .
"GMT");
889 header(
"Cache-Control: no-store, no-cache, must-revalidate");
890 header(
"Cache-Control: post-check=0, pre-check=0",
false);
891 header(
"Pragma: no-cache");
893 switch ($this->image_type) {
894 case self::SI_IMAGE_JPEG:
895 header(
"Content-Type: image/jpeg");
896 imagejpeg($this->im, null, 90);
898 case self::SI_IMAGE_GIF:
899 header(
"Content-Type: image/gif");
903 header(
"Content-Type: image/png");
908 imagedestroy($this->im);
930 for($i = 0; $i < strlen(
$code); ++$i) {
931 $letters[] =
$code{$i};
934 if ($format ==
'mp3') {
946 $fp = @fopen($this->wordlist_file,
'rb');
947 if (!$fp)
return false;
949 $fsize = filesize($this->wordlist_file);
950 if ($fsize < 128)
return false;
952 fseek($fp, rand(0, $fsize - 64), SEEK_SET);
953 $data = fread($fp, 64);
957 $start = @strpos(
$data,
"\n", rand(0, 56)) + 1;
958 $end = @strpos(
$data,
"\n", $start);
960 if ($start ===
false) {
962 }
else if ($end ===
false) {
963 $end = strlen(
$data);
966 return strtolower(substr(
$data, $start, $end - $start));
977 $code .= $this->charset{rand(0, $cslen - 1)};
995 if ($this->case_sensitive ==
false && preg_match(
'/[A-Z]/',
$code)) {
998 $this->case_sensitive =
true;
1001 $code_entered = trim( (($this->case_sensitive) ? $this->code_entered
1002 : strtolower($this->code_entered))
1004 $this->correct_code =
false;
1007 if (
$code == $code_entered) {
1008 $this->correct_code =
true;
1023 if (isset(
$_SESSION[
'securimage_code_value'][$this->
namespace]) &&
1024 trim(
$_SESSION[
'securimage_code_value'][$this->
namespace]) !=
'') {
1026 $_SESSION[
'securimage_code_ctime'][$this->
namespace]) ==
false) {
1029 }
else if ($this->use_sqlite_db ==
true && function_exists(
'sqlite_open')) {
1058 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1059 $ip = $_SERVER[
'REMOTE_ADDR'];
1062 $success = sqlite_query($this->sqlite_handle,
1063 "INSERT OR REPLACE INTO codes(ip, code, namespace, created)
1064 VALUES('$ip', '$code', '{$this->namespace}', $time)");
1075 $this->sqlite_handle =
false;
1077 if ($this->use_sqlite_db && function_exists(
'sqlite_open')) {
1078 $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666, $error);
1080 if ($this->sqlite_handle !==
false) {
1081 $res = sqlite_query($this->sqlite_handle,
"PRAGMA table_info(codes)");
1082 if (sqlite_num_rows(
$res) == 0) {
1083 sqlite_query($this->sqlite_handle,
"CREATE TABLE codes (ip VARCHAR(32) PRIMARY KEY, code VARCHAR(32) NOT NULL, namespace VARCHAR(32) NOT NULL, created INTEGER)");
1087 return $this->sqlite_handle !=
false;
1100 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1101 $ip = $_SERVER[
'REMOTE_ADDR'];
1102 $ns = sqlite_escape_string($this->
namespace);
1104 $res = sqlite_query($this->sqlite_handle,
"SELECT * FROM codes WHERE ip = '$ip' AND namespace = '$ns'");
1105 if (
$res && sqlite_num_rows(
$res) > 0) {
1121 if (is_resource($this->sqlite_handle)) {
1122 $ip = $_SERVER[
'REMOTE_ADDR'];
1123 $ns = sqlite_escape_string($this->
namespace);
1125 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE ip = '$ip' AND namespace = '$ns'");
1134 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1136 $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
1138 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE $now - created > $limit");
1150 if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
1152 }
else if (time() - $creation_time < $this->expiry_time) {
1183 $out_bpersample = 0;
1185 $removeChunks = array(
'LIST',
'DISP',
'NOTE');
1187 for ($i = 0; $i <
sizeof($letters); ++$i) {
1188 $letter = $letters[$i];
1189 $filename = $this->audio_path . strtoupper($letter) .
'.wav';
1193 if (
$data ===
false) {
1198 $header = substr(
$data, 0, 36);
1199 $info = unpack(
'NChunkID/VChunkSize/NFormat/NSubChunk1ID/'
1200 .
'VSubChunk1Size/vAudioFormat/vNumChannels/'
1201 .
'VSampleRate/VByteRate/vBlockAlign/vBitsPerSample',
1204 $dataPos = strpos(
$data,
'data');
1205 $out_channels = $info[
'NumChannels'];
1206 $out_samplert = $info[
'SampleRate'];
1207 $out_bpersample = $info[
'BitsPerSample'];
1209 if ($dataPos ===
false) {
1215 if ($info[
'AudioFormat'] != 1) {
1221 if ($info[
'SubChunk1Size'] != 16 && $info[
'SubChunk1Size'] != 18) {
1227 if ($info[
'SubChunk1Size'] > 16) {
1228 $header .= substr(
$data, 36, $info[
'SubChunk1Size'] - 16);
1233 $out_data = $header .
'data';
1238 foreach($removeChunks as $chunk) {
1239 $chunkPos = strpos(
$data, $chunk);
1240 if ($chunkPos !==
false) {
1241 $listSize = unpack(
'VSize', substr(
$data, $chunkPos + 4, 4));
1244 substr(
$data, $chunkPos + 8 + $listSize[
'Size']);
1246 $removed += $listSize[
'Size'] + 8;
1250 $dataSize = unpack(
'VSubchunk2Size', substr(
$data, $dataPos + 4, 4));
1251 $dataSize[
'Subchunk2Size'] -= $removed;
1252 $out_data .= substr(
$data, $dataPos + 8, $dataSize[
'Subchunk2Size'] * ($out_bpersample / 8));
1253 $numSamples += $dataSize[
'Subchunk2Size'];
1256 $filesize = strlen($out_data);
1257 $chunkSize = $filesize - 8;
1258 $dataCSize = $numSamples;
1260 $out_data = substr_replace($out_data, pack(
'V', $chunkSize), 4, 4);
1261 $out_data = substr_replace($out_data, pack(
'V', $numSamples), 40 + ($info[
'SubChunk1Size'] - 16), 4);
1275 $start = strpos(
$data,
'data') + 4;
1276 if ($start ===
false) $start = 44;
1278 $start += rand(1, 4);
1279 $datalen = strlen(
$data) - $start;
1282 for ($i = $start; $i < $datalen; $i += $step) {
1283 $ch = ord(
$data{$i});
1284 if ($ch == 0 || $ch == 255)
continue;
1286 if ($ch < 16 || $ch > 239) {
1289 $ch += rand(-12, 12);
1292 if ($ch < 0) $ch = 0;
else if ($ch > 255) $ch = 255;
1294 $data{$i} = chr($ch);
1309 return @file_get_contents(dirname(__FILE__) .
'/audio/error.wav');
1314 return 0.0001 * rand(0,9999);
1324 if ($color == null) {
1326 }
else if (is_string($color)) {
1332 }
else if (is_array($color) &&
sizeof($color) == 3) {
1369 $args = func_get_args();
1371 if (
sizeof($args) == 0) {
1375 }
else if (
sizeof($args) == 1) {
1377 if (substr($color, 0, 1) ==
'#') {
1378 $color = substr($color, 1);
1381 if (strlen($color) != 3 && strlen($color) != 6) {
1382 throw new InvalidArgumentException(
1383 'Invalid HTML color code passed to Securimage_Color'
1388 }
else if (
sizeof($args) == 3) {
1391 throw new InvalidArgumentException(
1392 'Securimage_Color constructor expects 0, 1 or 3 arguments; ' .
sizeof($args) .
' given'
1405 if ($red < 0) $red = 0;
1406 if ($red > 255) $red = 255;
1407 if ($green < 0) $green = 0;
1408 if ($green > 255) $green = 255;
1409 if ($blue < 0) $blue = 0;
1410 if ($blue > 255) $blue = 255;
1423 if (strlen($color) == 3) {
1424 $red = str_repeat(substr($color, 0, 1), 2);
1425 $green = str_repeat(substr($color, 1, 1), 2);
1426 $blue = str_repeat(substr($color, 2, 1), 2);
1428 $red = substr($color, 0, 2);
1429 $green = substr($color, 2, 2);
1430 $blue = substr($color, 4, 2);
1433 $this->r = hexdec($red);
1434 $this->g = hexdec($green);
1435 $this->b = hexdec($blue);