6 chars in length really. $width = ($max_word_length*(array_sum($font_widths)/sizeof($font_widths))+75); $height = 90; $im = ImageCreate($width, $height); $im2 = ImageCreate($width, $height); ////////////////////////////////////////////////////// ////// Avoid Brute Force Attacks: ////////////////////////////////////////////////////// if(empty($_SESSION['freecap_attempts'])) { $_SESSION['freecap_attempts'] = 1; } else { $_SESSION['freecap_attempts']++; // if more than ($max_attempts) refreshes, block further refreshes // can be negated by connecting with new session id // could get round this by storing num attempts in database against IP // could get round that by connecting with different IP (eg, using proxy servers) // in short, there's little point trying to avoid brute forcing // the best way to protect against BF attacks is to ensure the dictionary is not // accessible via the web or use random string option if($_SESSION['freecap_attempts']>$max_attempts) { $_SESSION['freecap_word_hash'] = false; $bg = ImageColorAllocate($im,255,255,255); ImageColorTransparent($im,$bg); $red = ImageColorAllocate($im, 255, 0, 0); // depending on how rude you want to be :-) //ImageString($im,5,0,20,"bugger off you spamming bastards!",$red); ImageString($im,5,15,20,"too many attempts",$red); sendImage($im); } } ////////////////////////////////////////////////////// ////// Functions: ////////////////////////////////////////////////////// function make_seed() { // from http://php.net/srand list($usec, $sec) = explode(' ', microtime()); return (float) $sec + ((float) $usec * 100000); } function rand_color() { global $bg_type,$rand_func; if($bg_type==3) { // needs darker colour.. return $rand_func(10,100); } else { return $rand_func(60,170); } } function myImageBlur($im) { // w00t. my very own blur function // in GD2, there's a gaussian blur function. bunch of bloody show-offs... :-) $width = imagesx($im); $height = imagesy($im); $temp_im = ImageCreateTrueColor($width,$height); $bg = ImageColorAllocate($temp_im,150,150,150); // preserves transparency if in orig image ImageColorTransparent($temp_im,$bg); // fill bg ImageFill($temp_im,0,0,$bg); // anything higher than 3 makes it totally unreadable // might be useful in a 'real' blur function, though (ie blurring pictures not text) $distance = 1; // use $distance=30 to have multiple copies of the word. not sure if this is useful. // blur by merging with itself at different x/y offsets: ImageCopyMerge($temp_im, $im, 0, 0, 0, $distance, $width, $height-$distance, 70); ImageCopyMerge($im, $temp_im, 0, 0, $distance, 0, $width-$distance, $height, 70); ImageCopyMerge($temp_im, $im, 0, $distance, 0, 0, $width, $height, 70); ImageCopyMerge($im, $temp_im, $distance, 0, 0, 0, $width, $height, 70); // remove temp image ImageDestroy($temp_im); return $im; } function sendImage($pic) { // output image with appropriate headers global $output,$im,$im2,$im3; header(base64_decode("WC1DYXB0Y2hhOiBmcmVlQ2FwIDEuNCAtIHd3dy5wdXJlbWFuZ28uY28udWs=")); switch($output) { // add other cases as desired case "jpg": header("Content-Type: image/jpeg"); ImageJPEG($pic); break; case "gif": header("Content-Type: image/gif"); ImageGIF($pic); break; case "png": default: header("Content-Type: image/png"); ImagePNG($pic); break; } // kill GD images (removes from memory) ImageDestroy($im); ImageDestroy($im2); ImageDestroy($pic); if(!empty($im3)) { ImageDestroy($im3); } exit(); } ////////////////////////////////////////////////////// ////// Choose Word: ////////////////////////////////////////////////////// if($use_dict==1) { // load dictionary and choose random word $words = @file($dict_location); $word = strtolower($words[$rand_func(0,sizeof($words)-1)]); // cut off line endings/other possible odd chars $word = ereg_replace("[^a-z]","",$word); // might be large file so forget it now (frees memory) $words = ""; unset($words); } else { // based on code originally by breakzero at hotmail dot com // (http://uk.php.net/manual/en/function.rand.php) // generate pseudo-random string // doesn't use ijtf as are easily mistaken // I'm not using numbers because the custom fonts I've created don't support anything other than // lowercase or space (but you can download new fonts or create your own using my GD fontmaker script) $consonants = 'bcdghklmnpqrsvwxyz'; $vowels = 'aeuo'; $word = ""; $wordlen = $rand_func(5,$max_word_length); for($i=0 ; $i<$wordlen ; $i++) { // don't allow to start with 'vowel' if($rand_func(0,4)>=2 && $i!=0) { $word .= $vowels{$rand_func(0,strlen($vowels)-1)}; } else { $word .= $consonants{$rand_func(0,strlen($consonants)-1)}; } } } // save hash of word for comparison // using hash so that if there's an insecurity elsewhere (eg on the form processor), // an attacker could only get the hash // also, shared servers usually give all users access to the session files // echo `ls /tmp`; and echo `more /tmp/someone_elses_session_file`; usually work // so even if your site is 100% secure, someone else's site on your server might not be // hence, even if attackers can read the session file, they can't get the freeCap word // (though most hashes are easy to brute force for simple strings) $_SESSION['freecap_word_hash'] = $hash_func($word); ////////////////////////////////////////////////////// ////// Fill BGs and Allocate Colours: ////////////////////////////////////////////////////// // set tag colour // have to do this before any distortion // (otherwise colour allocation fails when bg type is 1) $tag_col = ImageColorAllocate($im,10,10,10); $site_tag_col2 = ImageColorAllocate($im2,0,0,0); // set debug colours (text colours are set later) $debug = ImageColorAllocate($im, 255, 0, 0); $debug2 = ImageColorAllocate($im2, 255, 0, 0); // set background colour (can change to any colour not in possible $text_col range) // it doesn't matter as it'll be transparent or coloured over. // if you're using bg_type 3, you might want to try to ensure that the color chosen // below doesn't appear too much in any of your background images. $bg = ImageColorAllocate($im, 254, 254, 254); $bg2 = ImageColorAllocate($im2, 254, 254, 254); // set transparencies ImageColorTransparent($im,$bg); // im2 transparent to allow characters to overlap slightly while morphing ImageColorTransparent($im2,$bg2); // fill backgrounds ImageFill($im,0,0,$bg); ImageFill($im2,0,0,$bg2); if($bg_type!=0) { // generate noisy background, to be merged with CAPTCHA later // any suggestions on how best to do this much appreciated // sample code would be even better! // I'm not an OCR expert (hell, I'm not even an image expert; puremango.co.uk was designed in MsPaint) // so the noise models are based around my -guesswork- as to what would make it hard for an OCR prog // ideally, the character obfuscation would be strong enough not to need additional background noise // in any case, I hope at least one of the options given here provide some extra security! $im3 = ImageCreateTrueColor($width,$height); $temp_bg = ImageCreateTrueColor($width*1.5,$height*1.5); $bg3 = ImageColorAllocate($im3,255,255,255); ImageFill($im3,0,0,$bg3); $temp_bg_col = ImageColorAllocate($temp_bg,255,255,255); ImageFill($temp_bg,0,0,$temp_bg_col); // we draw all noise onto temp_bg // then if we're morphing, merge from temp_bg to im3 // or if not, just copy a $widthx$height portion of $temp_bg to $im3 // temp_bg is much larger so that when morphing, the edges retain the noise. if($bg_type==1) { // grid bg: // draw grid on x for($i=$rand_func(6,20) ; $i<$width*2 ; $i+=$rand_func(10,25)) { ImageSetThickness($temp_bg,$rand_func(2,6)); $text_r = $rand_func(100,150); $text_g = $rand_func(100,150); $text_b = $rand_func(100,150); $text_colour3 = ImageColorAllocate($temp_bg, $text_r, $text_g, $text_b); ImageLine($temp_bg,$i,0,$i,$height*2,$text_colour3); } // draw grid on y for($i=$rand_func(6,20) ; $i<$height*2 ; $i+=$rand_func(10,25)) { ImageSetThickness($temp_bg,$rand_func(2,6)); $text_r = $rand_func(100,150); $text_g = $rand_func(100,150); $text_b = $rand_func(100,150); $text_colour3 = ImageColorAllocate($temp_bg, $text_r, $text_g, $text_b); ImageLine($temp_bg,0,$i,$width*2, $i ,$text_colour3); } } else if($bg_type==2) { // draw squiggles! $bg3 = ImageColorAllocate($im3,255,255,255); ImageFill($im3,0,0,$bg3); ImageSetThickness($temp_bg,4); for($i=0 ; $i$prev_y-2); ImageCopy($im, $im2, $i, $y_pos, $i, 0, $font_pixelwidth, $height); // for debug: //ImageRectangle($im,$i,$y_pos+10,$i+$font_pixelwidth,$y_pos+70,$debug); } // for debug: //sendImage($im); ImageFilledRectangle($im2,0,0,$width,$height,$bg2); // randomly morph each character individually on x-axis // this is where the main distortion happens // massively improved since v1.2 $y_chunk = 1; $morph_factor = 1; $morph_x = 0; for($j=0 ; $j