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);
510 if ( session_id() ==
'' ) {
511 if (trim($this->session_name) !=
'') {
512 session_name($this->session_name);
523 $this->charset =
'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
524 $this->wordlist_file =
'./words/words.txt';
527 $this->gd_font_file =
'gdfonts/automatic.gdf';
528 $this->use_gd_font =
false;
529 $this->gd_font_size = 24;
530 $this->text_x_start = 15;
532 $this->ttf_file =
'./AHGBold.ttf';
543 new Securimage_color(0x0, 0x40, 0xCC),
553 $this->draw_lines_over_text =
true;
557 $this->signature_font =
'./AHGBold.ttf';
559 $this->audio_path =
'./audio/';
561 $this->session_name =
'';
562 $this->expiry_time = 900;
564 $this->sqlite_database =
'database/securimage.sqlite';
565 $this->use_sqlite_db =
false;
567 $this->sqlite_handle =
false;
583 function show($background_image =
"")
585 if($background_image !=
"" && is_readable($background_image)) {
586 $this->
bgimg = $background_image;
608 $this->code_entered =
$code;
610 return $this->correct_code;
627 header(
'Content-type: audio/x-wav');
630 header(
'Content-type: audio/mpeg');
634 header(
"Content-Disposition: attachment; filename=\"securimage_audio.{$ext}\"");
635 header(
'Cache-Control: no-store, no-cache, must-revalidate');
636 header(
'Expires: Sun, 1 Jan 2000 12:00:00 GMT');
637 header(
'Last-Modified: ' . gmdate(
'D, d M Y H:i:s') .
'GMT');
641 header(
'Content-Length: ' . strlen($audio));
655 if ($this->use_gd_font ==
true || $this->iscale ==
null || $this->iscale == 0) {
668 imagepalettecopy($this->tmpimg, $this->im);
677 if ($this->use_gd_font ==
false && is_readable($this->ttf_file)) $this->
distortedCopy();
696 $this->gdbgcolor = imagecolorallocate($this->im, $this->
image_bg_color->r??0, $this->image_bg_color->g??0, $this->image_bg_color->b??0);
710 $this->gdtextcolor = imagecolorallocatealpha($this->im, $this->
text_color->r, $this->text_color->g, $this->text_color->b, $alpha);
711 $this->gdlinecolor = imagecolorallocatealpha($this->im, $this->
line_color->r, $this->line_color->g, $this->line_color->b, $alpha);
713 $this->gdtextcolor = imagecolorallocate($this->im, $this->
text_color->r, $this->text_color->g, $this->text_color->b);
714 $this->gdlinecolor = imagecolorallocate($this->im, $this->
line_color->r, $this->line_color->g, $this->line_color->b);
719 $this->gdtextcolor = imagecolorallocate($this->im, $red, $green,$blue);
720 $this->gdlinecolor = imagecolorallocate($this->im, $red, $green, $blue);
723 $this->gdsignaturecolor = imagecolorallocate($this->im, $this->
signature_color->r??0, $this->signature_color->g??0, $this->signature_color->b??0);
726 $this->gdmulticolor = array();
733 $this->gdmulticolor[] = imagecolorallocatealpha($this->im,
$color->r,
$color->g,
$color->b, $alpha);
735 $this->gdmulticolor[] = imagecolorallocate($this->im,
$color->r,
$color->g,
$color->b);
749 imagefilledrectangle($this->im, 0, 0, $this->
image_width * $this->iscale, $this->
image_height * $this->iscale, $this->gdbgcolor);
750 imagefilledrectangle($this->tmpimg, 0, 0, $this->
image_width * $this->iscale, $this->
image_height * $this->iscale, $this->gdbgcolor);
752 if ($this->
bgimg ==
'') {
761 $dat = @getimagesize($this->
bgimg);
767 case 1: $newim = @imagecreatefromgif($this->
bgimg);
break;
768 case 2: $newim = @imagecreatefromjpeg($this->
bgimg);
break;
769 case 3: $newim = @imagecreatefrompng($this->
bgimg);
break;
770 case 15: $newim = @imagecreatefromwbmp($this->
bgimg);
break;
771 case 16: $newim = @imagecreatefromxbm($this->
bgimg);
break;
777 imagecopyresized($this->im, $newim, 0, 0, 0, 0, $this->
image_width, $this->
image_height, imagesx($newim), imagesy($newim));
792 while ((
$file = readdir($dh)) !==
false) {
793 if (preg_match(
'/(jpg|gif|png)$/i',
$file)) $images[] =
$file;
798 if (
sizeof($images) > 0) {
821 $theta = ($this->
frand()-0.5) * M_PI * 0.7;
822 $w = $this->image_width;
823 $len = rand(
$w * 0.4,
$w * 0.7);
826 $k = $this->
frand() * 0.6 + 0.2;
828 $phi = $this->
frand() * 6.28;
830 $dx =
$step * cos($theta);
831 $dy =
$step * sin($theta);
833 $amp = 1.5 * $this->
frand() / ($k + 5.0 / $len);
834 $x0 =
$x - 0.5 * $len * cos($theta);
835 $y0 = $y - 0.5 * $len * sin($theta);
837 $ldx = round(-$dy * $lwid);
838 $ldy = round($dx * $lwid);
841 $x = $x0 +
$i * $dx + $amp * $dy * sin($k *
$i *
$step + $phi);
842 $y = $y0 +
$i * $dy - $amp * $dx * sin($k *
$i *
$step + $phi);
845 imagefilledrectangle($this->im,
$x, $y,
$x + $lwid, $y + $lwid, $this->gdlinecolor);
861 if ($this->use_gd_font ==
true || !is_readable($this->ttf_file??
"")) {
862 if (!is_int($this->gd_font_file)) {
863 $font = @imageloadfont($this->gd_font_file??
"");
864 if ($font ==
false) {
865 trigger_error(
"Failed to load GD Font file {$this->gd_font_file} ", E_USER_WARNING);
869 $font = $this->gd_font_file;
872 imagestring($this->im, $font, $this->text_x_start, ($this->
image_height / 2) - ($this->gd_font_size / 2), $this->code, $this->gdtextcolor);
874 $font_size = $height2 * .35;
875 $bb = imagettfbbox($font_size, 0, $this->ttf_file, $this->code);
876 $tx = $bb[4] - $bb[0];
877 $ty = $bb[5] - $bb[1];
878 $x = floor($width2 / 2 - $tx / 2 - $bb[0]);
879 $y = round($height2 / 2 - $ty / 2 - $bb[1]);
881 $strlen = strlen($this->code);
886 imagettftext($this->tmpimg, $font_size, 0,
$x, $y, $this->gdtextcolor, $this->ttf_file, $this->code);
888 for(
$i = 0;
$i < $strlen; ++
$i) {
890 $y = rand($y - 5, $y + 5);
892 $font_color = $this->gdmulticolor[rand(0,
sizeof($this->gdmulticolor) - 1)];
894 $font_color = $this->gdtextcolor;
897 $ch = $this->code[
$i];
899 imagettftext($this->tmpimg, $font_size, $angle,
$x, $y, $font_color, $this->ttf_file, $ch);
904 if (strpos(
'abcdeghknopqsuvxyz', $ch) !==
false) {
905 $min_x = $font_size - ($this->iscale * 6);
906 $max_x = $font_size - ($this->iscale * 6);
907 }
else if (strpos(
'ilI1', $ch) !==
false) {
908 $min_x = $font_size / 5;
909 $max_x = $font_size / 3;
910 }
else if (strpos(
'fjrt', $ch) !==
false) {
911 $min_x = $font_size - ($this->iscale * 12);
912 $max_x = $font_size - ($this->iscale * 12);
913 }
else if ($ch ==
'wm') {
915 $max_x = $font_size + ($this->iscale * 3);
917 $min_x = $font_size + ($this->iscale * 2);
918 $max_x = $font_size + ($this->iscale * 5);
921 $x += rand((
int)$min_x,(
int) $max_x);
944 for (
$i = 0;
$i < $numpoles; ++
$i) {
952 $bgCol = imagecolorat($this->tmpimg, 0, 0);
953 $width2 = $this->iscale * $this->image_width;
954 $height2 = $this->iscale * $this->image_height;
956 imagepalettecopy($this->im, $this->tmpimg);
959 for (
$ix = 0;
$ix < $this->image_width; ++
$ix) {
960 for ($iy = 0; $iy < $this->image_height; ++$iy) {
964 for (
$i = 0;
$i < $numpoles; ++
$i) {
967 if ($dx == 0 && $dy == 0)
continue;
969 $r = sqrt($dx * $dx + $dy * $dy);
972 $rscale = $amp[
$i] * sin(3.14 *
$r /
$rad[
$i]);
982 $c = imagecolorat($this->tmpimg, (
int)
$x,(
int) $y);
986 imagesetpixel($this->im,
$ix, $iy,
$c);
1001 $this->code =
false;
1003 if ($this->
use_wordlist && is_readable($this->wordlist_file)) {
1007 if ($this->code ==
false) {
1025 for(
$i = 1, $cslen = strlen($this->charset??
"");
$i <= $len; ++
$i) {
1026 $code .= $this->charset[rand(0, $cslen - 1)];
1040 $fp = @fopen($this->wordlist_file,
'rb');
1041 if (!$fp)
return false;
1043 $fsize = filesize($this->wordlist_file);
1044 if ($fsize < 32)
return false;
1052 fseek($fp, rand(0, $fsize -
$max), SEEK_SET);
1053 $data = fread($fp, 128);
1055 $data = preg_replace(
"/\r?\n/",
"\n",
$data);
1071 header(
"Expires: Mon, 26 Jul 1997 05:00:00 GMT");
1072 header(
"Last-Modified: " . gmdate(
"D, d M Y H:i:s") .
"GMT");
1073 header(
"Cache-Control: no-store, no-cache, must-revalidate");
1074 header(
"Cache-Control: post-check=0, pre-check=0",
false);
1075 header(
"Pragma: no-cache");
1080 header(
"Content-Type: image/jpeg");
1081 imagejpeg($this->im,
null, 90);
1085 header(
"Content-Type: image/gif");
1086 imagegif($this->im);
1090 header(
"Content-Type: image/png");
1091 imagepng($this->im);
1095 imagedestroy($this->im);
1121 if ($format ==
'mp3') {
1136 if (is_dir($audio_directory) && is_readable($audio_directory)) {
1137 $this->audio_path = $audio_directory;
1152 $_SESSION[
'securimage_code_value'] = strtolower($this->code);
1153 $_SESSION[
'securimage_code_ctime'] = time();
1169 if (isset($_SESSION[
'securimage_code_value']) && trim($_SESSION[
'securimage_code_value']) !=
'') {
1170 if ($this->
isCodeExpired($_SESSION[
'securimage_code_ctime']) ==
false) {
1171 $code = $_SESSION[
'securimage_code_value'];
1173 }
else if ($this->use_sqlite_db ==
true && function_exists(
'sqlite_open')) {
1183 $this->correct_code =
false;
1187 $this->correct_code =
true;
1188 $_SESSION[
'securimage_code_value'] =
'';
1189 $_SESSION[
'securimage_code_ctime'] =
'';
1203 if (isset($_SESSION[
'securimage_code_value']) && !empty($_SESSION[
'securimage_code_value'])) {
1204 return strtolower($_SESSION[
'securimage_code_value']);
1206 if ($this->sqlite_handle ==
false) $this->
openDatabase();
1220 return $this->correct_code;
1237 foreach ($letters as
$letter) {
1238 $filename = $this->audio_path . strtoupper(
$letter) .
'.wav';
1240 $fp = fopen($filename,
'rb');
1244 $data = fread($fp, filesize($filename));
1247 $body = substr(
$data, 44);
1250 $data = unpack(
'NChunkID/VChunkSize/NFormat/NSubChunk1ID/VSubChunk1Size/vAudioFormat/vNumChannels/VSampleRate/VByteRate/vBlockAlign/vBitsPerSample',
$header);
1252 $file[
'sub_chunk1_id'] =
$data[
'SubChunk1ID'];
1253 $file[
'bits_per_sample'] =
$data[
'BitsPerSample'];
1258 $file[
'data'] = $body;
1260 if ( (
$p = strpos(
$file[
'data'],
'LIST')) !==
false) {
1262 $info = substr(
$file[
'data'],
$p + 4, 8);
1263 $data = unpack(
'Vlength/Vjunk', $info);
1273 $data_len += strlen(
$file[
'data']);
1279 for(
$i = 0;
$i <
sizeof($files); ++
$i) {
1281 $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(
' '));
1283 $out_data .= pack(
'VvvVVvv',
1285 $files[
$i][
'format'],
1286 $files[
$i][
'channels'],
1287 $files[
$i][
'sample_rate'],
1288 $files[
$i][
'sample_rate'] * (($files[
$i][
'bits_per_sample'] * $files[
$i][
'channels']) / 8),
1289 ($files[
$i][
'bits_per_sample'] * $files[
$i][
'channels']) / 8,
1290 $files[
$i][
'bits_per_sample'] );
1292 $out_data .= pack(
'C4', ord(
'd'), ord(
'a'), ord(
't'), ord(
'a'));
1294 $out_data .= pack(
'V', $data_len);
1297 $out_data .= $files[
$i][
'data'];
1314 if ($format ==
'wav') {
1326 if ($ch < 9 || $ch > 119)
continue;
1328 $data[
$i] = chr($ch + rand(-8, 8));
1345 foreach ($letters as
$letter) {
1346 $filename = $this->audio_path . strtoupper(
$letter) .
'.mp3';
1348 $fp = fopen($filename,
'rb');
1349 $data = fread($fp, filesize($filename));
1369 return 0.0001*rand(0,9999);
1381 if ($this->use_gd_font) {
1385 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->
image_signature);
1386 $textlen = $bbox[2] - $bbox[0];
1390 imagettftext($this->im, 10, 0,
$x, $y, $this->gdsignaturecolor, $this->signature_font, $this->
image_signature);
1403 return strtolower(md5($_SERVER[
'REMOTE_ADDR']));
1415 $this->sqlite_handle =
false;
1417 if ($this->use_sqlite_db && function_exists(
'sqlite_open')) {
1418 $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666,
$error);
1420 if ($this->sqlite_handle !==
false) {
1421 $res = sqlite_query($this->sqlite_handle,
"PRAGMA table_info(codes)");
1422 if (sqlite_num_rows(
$res) == 0) {
1423 sqlite_query($this->sqlite_handle,
"CREATE TABLE codes (iphash VARCHAR(32) PRIMARY KEY, code VARCHAR(32) NOT NULL, created INTEGER)");
1427 return $this->sqlite_handle !=
false;
1430 return $this->sqlite_handle;
1446 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1449 $code = $_SESSION[
'securimage_code_value'];
1450 $success = sqlite_query($this->sqlite_handle,
"INSERT OR REPLACE INTO codes(iphash, code, created) VALUES('$ip', '$code', $time)");
1453 return $success !==
false;
1467 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1470 $res = sqlite_query($this->sqlite_handle,
"SELECT * FROM codes WHERE iphash = '$ip'");
1471 if (
$res && sqlite_num_rows(
$res) > 0) {
1491 if ($this->sqlite_handle !==
false) {
1494 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE iphash = '$ip'");
1506 if ($this->use_sqlite_db && $this->sqlite_handle !==
false) {
1508 $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
1510 sqlite_query($this->sqlite_handle,
"DELETE FROM codes WHERE $now - created > $limit");
1526 if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
1528 }
else if (time() - $creation_time < $this->expiry_time) {
1578 if ($green ==
null && $blue ==
null && preg_match(
'/^#[a-f0-9]{3,6}$/i', $red)) {
1579 $col = substr($red, 1);
1580 if (strlen($col) == 3) {
1581 $red = str_repeat(substr($col, 0, 1), 2);
1582 $green = str_repeat(substr($col, 1, 1), 2);
1583 $blue = str_repeat(substr($col, 2, 1), 2);
1585 $red = substr($col, 0, 2);
1586 $green = substr($col, 2, 2);
1587 $blue = substr($col, 4, 2);
1590 $red = hexdec($red);
1591 $green = hexdec($green);
1592 $blue = hexdec($blue);
1594 if ($red < 0) $red = 0;
1595 if ($red > 255) $red = 255;
1596 if ($green < 0) $green = 0;
1597 if ($green > 255) $green = 255;
1598 if ($blue < 0) $blue = 0;
1599 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