<?php
/**
* Usage
* ReCaptcha('generate') - generate Captcha, return array('key'=>PUBLIC_KEY, 'image'=> IMAGE_FILE_NAME)
* ReCaptcha('check', array('public'=>PUBLIC_KEY, 'private'=>PRIVATE_KEY[user_input_value] )) - check captcha, return true/false
* ReCaptcha('change', array('public'=>PUBLIC_KEY) - generate Captcha, return array('key'=>PUBLIC_KEY, 'image'=> IMAGE_FILE_NAME), and delete old cartcha image
*/
define('SITE_PATH_DOCROOT', dirname(__FILE__));
function ReCaptcha($do, $params = array())
{
$captcha = null;
switch ($do){
case 'generate':
$captcha = new ReCaptchaClass;
return array('key'=>$captcha->PublicKey, 'image'=>$captcha->CaptchaFileName);
break;
case 'check':
if((array_key_exists('public', $params))&&(array_key_exists('private', $params))){
$captcha = new ReCaptchaClass(false);
return $captcha->CheckCaptcha($params['public'], $params['private']);
} else {
return false;
}
break;
case 'change':
if(array_key_exists('public_key', $params)){
$captcha = new ReCaptchaClass(false);
$fname = $captcha->GetFileName($params['public_key']);
if(is_file($fname)){
@unlink($fname);
}
$captcha = new ReCaptchaClass;
return array('key'=>$captcha->PublicKey, 'image'=>$captcha->CaptchaFileName);
}
break;
}
}
class ReCaptchaClass
{
public $CaptchaFileName = null;
public $Directory = 'temp_captcha';
public $FontDirectory = 'fonts';
public $TTFRange = array('comic.ttf','impact.ttf');
public $MaxChars = 5;
public $MinSize = 10;
public $MaxSize = 18;
public $MaxRotation = 20; // [-30 .. 30]
public $NoiseChars = false;
public $WebSafeColors = false;
public $SecretString = 'MY SECRET CODE!!!';
public $SecretPosition = 15; // [1 .. 32]
public $OutOfDateTime = 86400; // One day
public $PublicKey = null;
private $lx;
private $ly;
private $jpg_quality = 40;
private $noise_factor = 9;
private $nb_noise = null;
private $key = null;
private $privateKey = null;
private $filename = null;
private $gdVersion = 0;
private $r = null;
private $g = null;
private $b = null;
private $TTFfile = null;
public function __construct($generate = true){
$gd_info = gd_info();
$this->gdVersion = $gd_info['GD Version'];
$this->_mandatory = true;
if(empty($this->gdVersion))
{
throw new Exception('ТЕПЕРЬ Я ПРАВИЛЬНО УПАЛ');
}
foreach($this->TTFRange as $key => $font)
{
if(!IsReadable($this->FontDirectory . DIRECTORY_SEPARATOR . $font))
{
unset($this->TTFRange[$key]);
}
}
if(count($this->TTFRange) < 1)
{
throw new Exception('No Truetypefont available');
}
$this->ChangeFont();
$this->nb_noise = $this->NoiseChars ? ($this->MaxChars * $this->noise_factor) : null;
$this->lx = ($this->MaxChars + 1) * (int)(($this->MaxSize + $this->MinSize) / 1.5);
$this->ly = (int)(2.4 * $this->MaxSize);
$this->key = md5($this->SecretString);
$this->PublicKey = substr(md5(uniqid(rand(),true)), 0, $this->MaxChars);
$this->GarbageCollector();
if($generate){
$this->GenerateCaptchaImage();
}
}
public function CheckCaptcha($public, $private)
{
$res = false;
// when check, destroy picture on disk
if(IsReadable($this->GetFileName($public)))
{
//$res = @unlink($this->GetFileName($public)) ? true : false;
$res = (strtolower($private) == strtolower($this->GeneratePrivateKey($public))) ? true : false;
}
return $res;
}
public function GenerateCaptchaImage()
{
$private_key = $this->GeneratePrivateKey();
// create Image and set the apropriate function depending on GD-Version & websafecolor-value
if($this->gdVersion >= 2 && !$this->WebSafeColors)
{
$func1 = 'imagecreatetruecolor';
$func2 = 'imagecolorallocate';
}
else
{
$func1 = 'imageCreate';
$func2 = 'imagecolorclosest';
}
$image = $func1($this->lx,$this->ly);
// Set Backgroundcolor
$this->RandomColor(220, 255);
$back = @imagecolorallocate($image, $this->r, $this->g, $this->b);
@ImageFilledRectangle($image, 0, 0, $this->lx, $this->ly, $back);
// allocates the 216 websafe color palette to the image
if($this->gdVersion < 2 || $this->WebSafeColors) $this->MakeWebSafeColors($image);
// fill with noise or grid
if($this->nb_noise > 0)
{
// random characters in background with random position, angle, color
for($i=0; $i < $this->nb_noise; $i++)
{
srand((double)microtime()*1000000);
$size = intval(rand((int)($this->MinSize / 2.3), (int)($this->MaxSize / 1.7)));
srand((double)microtime()*1000000);
$angle = intval(rand(0, 360));
srand((double)microtime()*1000000);
$x = intval(rand(0, $this->lx));
srand((double)microtime()*1000000);
$y = intval(rand(0, (int)($this->ly - ($size / 5))));
$this->RandomColor(160, 224);
$color = $func2($image, $this->r, $this->g, $this->b);
srand((double)microtime()*1000000);
$text = chr(intval(rand(45,250)));
@ImageTTFText($image, $size, $angle, $x, $y, $color, $this->ChangeFont(), $text);
}
}
else
{
// generate grid
for($i=0; $i < $this->lx; $i += (int)($this->MinSize / 1.5))
{
$this->RandomColor(160, 224);
$color = $func2($image, $this->r, $this->g, $this->b);
@imageline($image, $i, 0, $i, $this->ly, $color);
}
for($i=0 ; $i < $this->ly; $i += (int)($this->MaxSize / 1.8))
{
$this->RandomColor(160, 224);
$color = $func2($image, $this->r, $this->g, $this->b);
@imageline($image, 0, $i, $this->lx, $i, $color);
}
}
// generate Text
for($i=0, $x = intval(rand($this->MinSize, $this->MaxSize)); $i < $this->MaxChars; $i++)
{
$text = strtoupper(substr($private_key, $i, 1));
srand((double)microtime()*1000000);
$angle = intval(rand(($this->MaxRotation * -1), $this->MaxRotation));
srand((double)microtime()*1000000);
$size = intval(rand($this->MinSize, $this->MaxSize));
srand((double)microtime()*1000000);
$y = intval(rand((int)($size * 1.5), (int)($this->ly - ($size / 7))));
$this->RandomColor(0, 127);
$color = $func2($image, $this->r, $this->g, $this->b);
$this->RandomColor(0, 127);
$shadow = $func2($image, $this->r + 127, $this->g + 127, $this->b + 127);
@ImageTTFText($image, $size, $angle, $x + (int)($size / 15), $y, $shadow, $this->ChangeFont(), $text);
@ImageTTFText($image, $size, $angle, $x, $y - (int)($size / 15), $color, $this->TTFfile, $text);
$x += (int)($size + ($this->MinSize / 5));
}
@ImageJPEG($image, $this->GetFileName(), $this->jpg_quality);
$res = IsReadable($this->GetFileName());
@ImageDestroy($image);
if(!$res)
{
throw new Exception(sprintf('Unable to safe captcha-image.'));
}
$this->CaptchaFileName = $this->GetRelativePath();
}
private function GarbageCollector()
{
$d = opendir($this->Directory);
while (false !== ($file = readdir($d)))
{
$fmtime = filemtime($this->Directory . DIRECTORY_SEPARATOR . $file) + $this->OutOfDateTime;
if($fmtime < time() && strstr($file, 'captcha_'))
{
@unlink($this->Directory . DIRECTORY_SEPARATOR . $file);
}
}
}
private function ChangeFont()
{
if(is_array($this->TTFRange))
{
srand((float)microtime() * 10000000);
$key = array_rand($this->TTFRange);
$this->TTFfile = $this->FontDirectory . DIRECTORY_SEPARATOR . $this->TTFRange[$key];
}
else
{
$this->TTFfile = $this->FontDirectory . DIRECTORY_SEPARATOR . $this->TTFRange;
}
return $this->TTFfile;
}
private function GeneratePrivateKey($public = '')
{
$public = empty($public) ? $this->PublicKey : $public;
$key = substr(md5($this->key . $public), 16 - $this->MaxChars / 2, $this->MaxChars);
$arr = str_split($key);
$key = '';
foreach($arr as $value)
{
$key .= substr(ord($value), strlen(ord($value)) - 1);
}
$key = substr($key, 0, $this->MaxChars);
return $key;
}
public function GetFileName($public = '')
{
$public = empty($public) ? $this->PublicKey : $public;
return $this->Directory . DIRECTORY_SEPARATOR . 'captcha_' . $public . ".jpg";
}
private function GetRelativePath()
{
return str_replace("\\", '/', str_replace(SITE_PATH_DOCROOT, '', $this->GetFileName()));
}
private function RandomColor($min, $max)
{
srand((double)microtime() * 1000000);
$this->r = intval(rand($min,$max));
srand((double)microtime() * 1000000);
$this->g = intval(rand($min,$max));
srand((double)microtime() * 1000000);
$this->b = intval(rand($min,$max));
}
private function MakeWebSafeColors(&$image)
{
for($r = 0; $r <= 255; $r += 51)
{
for($g = 0; $g <= 255; $g += 51)
{
for($b = 0; $b <= 255; $b += 51)
{
$color = imagecolorallocate($image, $r, $g, $b);
}
}
}
}
}
function IsReadable($fileName)
{
$fp = @fopen($fileName, "r", true);
$is_readable = is_resource($fp);
if($is_readable)
{
fclose($fp);
}
return $is_readable;
}
?>
Создаём 2 папки в этом же каталоге: "temp_captcha" - туда складываем картинки и "fonts", туда ложим фонты. Либо сами смотрим по конфигу класса. Фонты прилагаю. Хотите юзать свои - юзайте, только конф класса подправьте.
p.s. функцию IsReadable тупо вырезал, потому как и класс надо было вырезать. Хотите - перенесите в класс. Да и саму функцию ReCaptcha можно убрать, но это так у меня - чтобы удобней было xD