86if (!defined(
'SI_IMAGE_JPEG'))
87 define(
'SI_IMAGE_JPEG', 1);
91if (!defined(
'SI_IMAGE_PNG'))
92 define(
'SI_IMAGE_PNG', 2);
97if (!defined(
'SI_IMAGE_GIF'))
98 define(
'SI_IMAGE_GIF', 3);
509 if ( session_id() ==
'' ) {
510 if (trim($this->session_name) !=
'') {
511 session_name($this->session_name);
522 $this->charset =
'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
523 $this->wordlist_file =
'./words/words.txt';
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;
531 $this->ttf_file =
'./AHGBold.ttf';
542 new Securimage_color(0x0, 0x40, 0xCC),
552 $this->draw_lines_over_text =
true;
556 $this->signature_font =
'./AHGBold.ttf';
558 $this->audio_path =
'./audio/';
560 $this->session_name =
'';
561 $this->expiry_time = 900;
563 $this->sqlite_database =
'database/securimage.sqlite';
564 $this->use_sqlite_db =
false;
566 $this->sqlite_handle =
false;
582 function show($background_image =
"")
584 if($background_image !=
"" && is_readable($background_image)) {
585 $this->
bgimg = $background_image;
607 $this->code_entered =
$code;
626 header(
'Content-type: audio/x-wav');
629 header(
'Content-type: audio/mpeg');
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');
640 header(
'Content-Length: ' . strlen($audio));
654 if ($this->use_gd_font ==
true || $this->iscale ==
null || $this->iscale == 0) {
667 imagepalettecopy($this->tmpimg, $this->im);
676 if ($this->use_gd_font ==
false && is_readable($this->ttf_file)) $this->
distortedCopy();
695 $this->gdbgcolor = imagecolorallocate($this->im, $this->
image_bg_color->r??0, $this->image_bg_color->g??0, $this->image_bg_color->b??0);
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);
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);
718 $this->gdtextcolor = imagecolorallocate($this->im, $red, $green,$blue);
719 $this->gdlinecolor = imagecolorallocate($this->im, $red, $green, $blue);
722 $this->gdsignaturecolor = imagecolorallocate($this->im, $this->
signature_color->r??0, $this->signature_color->g??0, $this->signature_color->b??0);
725 $this->gdmulticolor = array();
732 $this->gdmulticolor[] = imagecolorallocatealpha($this->im,
$color->r,
$color->g,
$color->b, $alpha);
734 $this->gdmulticolor[] = imagecolorallocate($this->im,
$color->r,
$color->g,
$color->b);
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);
751 if ($this->
bgimg ==
'') {
760 $dat = @getimagesize($this->
bgimg);
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;
776 imagecopyresized($this->im, $newim, 0, 0, 0, 0, $this->
image_width, $this->
image_height, imagesx($newim), imagesy($newim));
791 while ((
$file = readdir($dh)) !==
false) {
792 if (preg_match(
'/(jpg|gif|png)$/i',
$file)) $images[] =
$file;
797 if (
sizeof($images) > 0) {
820 $theta = ($this->
frand()-0.5) * M_PI * 0.7;
822 $len = rand(
$w * 0.4,
$w * 0.7);
825 $k = $this->
frand() * 0.6 + 0.2;
827 $phi = $this->
frand() * 6.28;
829 $dx =
$step * cos($theta);
830 $dy =
$step * sin($theta);
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);
836 $ldx = round(-$dy * $lwid);
837 $ldy = round($dx * $lwid);
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);
858 if ($this->use_gd_font ==
true || !is_readable($this->ttf_file??
"")) {
859 if (!is_int($this->gd_font_file)) {
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);
869 imagestring($this->im, $font, $this->text_x_start, ($this->
image_height / 2) - ($this->gd_font_size / 2), $this->code, $this->gdtextcolor);
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]);
878 $strlen = strlen($this->code);
883 imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code);
885 for(
$i = 0;
$i < $strlen; ++
$i) {
887 $y = rand($y - 5, $y + 5);
889 $font_color = $this->gdmulticolor[rand(0,
sizeof($this->gdmulticolor) - 1)];
894 $ch = $this->code[
$i];
896 imagettftext($this->tmpimg, $font_size, $angle, $x, $y, $font_color, $this->ttf_file, $ch);
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') {
912 $max_x = $font_size + ($this->iscale * 3);
914 $min_x = $font_size + ($this->iscale * 2);
915 $max_x = $font_size + ($this->iscale * 5);
918 $x += rand((
int)$min_x,(
int) $max_x);
941 for (
$i = 0;
$i < $numpoles; ++
$i) {
949 $bgCol = imagecolorat($this->tmpimg, 0, 0);
953 imagepalettecopy($this->im, $this->tmpimg);
961 for (
$i = 0;
$i < $numpoles; ++
$i) {
964 if ($dx == 0 && $dy == 0)
continue;
966 $r = sqrt($dx * $dx + $dy * $dy);
969 $rscale = $amp[
$i] * sin(3.14 *
$r /
$rad[
$i]);
978 if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
979 $c = imagecolorat($this->tmpimg, (
int) $x,(
int) $y);
983 imagesetpixel($this->im,
$ix, $iy, $c);
1000 if ($this->
use_wordlist && is_readable($this->wordlist_file)) {
1004 if ($this->code ==
false) {
1022 for(
$i = 1, $cslen = strlen($this->charset??
"");
$i <= $len; ++
$i) {
1023 $code .= $this->charset[rand(0, $cslen - 1)];
1037 $fp = @fopen($this->wordlist_file,
'rb');
1038 if (!$fp)
return false;
1040 $fsize = filesize($this->wordlist_file);
1041 if ($fsize < 32)
return false;
1049 fseek($fp, rand(0, $fsize -
$max), SEEK_SET);
1050 $data = fread($fp, 128);
1052 $data = preg_replace(
"/\r?\n/",
"\n",
$data);
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");
1077 header(
"Content-Type: image/jpeg");
1078 imagejpeg($this->im,
null, 90);
1082 header(
"Content-Type: image/gif");
1083 imagegif($this->im);
1087 header(
"Content-Type: image/png");
1088 imagepng($this->im);
1092 imagedestroy($this->im);
1118 if ($format ==
'mp3') {
1133 if (is_dir($audio_directory) && is_readable($audio_directory)) {
1134 $this->audio_path = $audio_directory;
1149 $_SESSION[
'securimage_code_value'] = strtolower($this->code);
1150 $_SESSION[
'securimage_code_ctime'] = time();
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'];
1170 }
else if ($this->use_sqlite_db ==
true && function_exists(
'sqlite_open')) {
1180 $this->correct_code =
false;
1184 $this->correct_code =
true;
1185 $_SESSION[
'securimage_code_value'] =
'';
1186 $_SESSION[
'securimage_code_ctime'] =
'';
1200 if (isset($_SESSION[
'securimage_code_value']) && !empty($_SESSION[
'securimage_code_value'])) {
1201 return strtolower($_SESSION[
'securimage_code_value']);
1203 if ($this->sqlite_handle ==
false) $this->
openDatabase();
1234 foreach ($letters as
$letter) {
1235 $filename = $this->audio_path . strtoupper(
$letter) .
'.wav';
1237 $fp = fopen($filename,
'rb');
1241 $data = fread($fp, filesize($filename));
1244 $body = substr(
$data, 44);
1247 $data = unpack(
'NChunkID/VChunkSize/NFormat/NSubChunk1ID/VSubChunk1Size/vAudioFormat/vNumChannels/VSampleRate/VByteRate/vBlockAlign/vBitsPerSample',
$header);
1249 $file[
'sub_chunk1_id'] =
$data[
'SubChunk1ID'];
1250 $file[
'bits_per_sample'] =
$data[
'BitsPerSample'];
1255 $file[
'data'] = $body;
1257 if ( (
$p = strpos(
$file[
'data'],
'LIST')) !==
false) {
1259 $info = substr(
$file[
'data'],
$p + 4, 8);
1260 $data = unpack(
'Vlength/Vjunk', $info);
1270 $data_len += strlen(
$file[
'data']);
1276 for(
$i = 0;
$i <
sizeof($files); ++
$i) {
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(
' '));
1280 $out_data .= pack(
'VvvVVvv',
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'] );
1289 $out_data .= pack(
'C4', ord(
'd'), ord(
'a'), ord(
't'), ord(
'a'));
1291 $out_data .= pack(
'V', $data_len);
1294 $out_data .= $files[
$i][
'data'];
1311 if ($format ==
'wav') {
1323 if ($ch < 9 || $ch > 119)
continue;
1325 $data[
$i] = chr($ch + rand(-8, 8));
1342 foreach ($letters as
$letter) {
1343 $filename = $this->audio_path . strtoupper(
$letter) .
'.mp3';
1345 $fp = fopen($filename,
'rb');
1346 $data = fread($fp, filesize($filename));
1366 return 0.0001*rand(0,9999);
1378 if ($this->use_gd_font) {
1382 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->
image_signature);
1383 $textlen = $bbox[2] - $bbox[0];
1387 imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->
image_signature);
1400 return strtolower(md5($_SERVER[
'REMOTE_ADDR']));
1412 $this->sqlite_handle =
false;
1414 if ($this->use_sqlite_db && function_exists(
'sqlite_open')) {
1415 $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666,
$error);
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)");
1424 return $this->sqlite_handle !=
false;
1443 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1446 $code = $_SESSION[
'securimage_code_value'];
1447 $success = sqlite_query($this->sqlite_handle,
"INSERT OR REPLACE INTO codes(iphash, code, created) VALUES('$ip', '$code', $time)");
1450 return $success !==
false;
1464 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1467 $res = sqlite_query($this->sqlite_handle,
"SELECT * FROM codes WHERE iphash = '$ip'");
1468 if (
$res && sqlite_num_rows(
$res) > 0) {
1472 $code =
$res[
'code'];
1488 if ($this->sqlite_handle !==
false) {
1491 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE iphash = '$ip'");
1503 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1505 $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
1507 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE $now - created > $limit");
1523 if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
1525 }
else if (time() - $creation_time < $this->expiry_time) {
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);
1582 $red = substr($col, 0, 2);
1583 $green = substr($col, 2, 2);
1584 $blue = substr($col, 4, 2);
1587 $red = hexdec($red);
1588 $green = hexdec($green);
1589 $blue = hexdec($blue);
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;
catch(Exception $exc) if(! $g_user->can_write_action($ag_id)) $r
foreach($array as $idx=> $m) $w
__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.
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.
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.
purgeOldCodesFromDatabase()
Purge codes over a day old from database.
outputAudioFile()
Output audio file with HTTP headers to browser.
$text_transparency_percentage
drawWord()
Draw the CAPTCHA code over the image.
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.
setAudioPath($audio_directory)
Set the path to the audio directory.
createCode()
Create a code and save to the session.
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.
generateMP3($letters)
Generate an mp3 file by concatenating individual files.
doImage()
Generate and output the image.
distortedCopy()
Warp text from temporary image onto final image.
setBackground()
Set the background of the CAPTCHA image.
show($background_image="")
Generate a code and output the image to the browser.
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.
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.
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 text_transparency_percentage
$img background_directory
$img use_transparent_text