From a3ce06f2636e436f6ea9f8ec7b8cd51bfd787260 Mon Sep 17 00:00:00 2001 From: Gregwar Date: Fri, 2 Dec 2011 19:26:31 +0100 Subject: [PATCH] [Generator] Fingerprinting CAPTCHAs to keep the same image between two requests (fixes #11) --- Generator/CaptchaGenerator.php | 67 ++++++++++++++++++++++++++++------ Type/CaptchaType.php | 12 +++++- Validator/CaptchaValidator.php | 4 ++ 3 files changed, 70 insertions(+), 13 deletions(-) diff --git a/Generator/CaptchaGenerator.php b/Generator/CaptchaGenerator.php index 617bce2..2707406 100644 --- a/Generator/CaptchaGenerator.php +++ b/Generator/CaptchaGenerator.php @@ -39,13 +39,26 @@ class CaptchaGenerator { */ public $expiration; + /** + * Random fingerprint + * Useful to be able to regenerate exactly the same image + * @var array + */ + public $fingerprint; + + /** + * Should fingerprint be used ? + * @var boolean + */ + public $use_fingerprint; + /** * The captcha code * @var string */ public $value; - public function __construct($value, $imageFolder, $webPath, $gcFreq, $expiration, $font) + public function __construct($value, $imageFolder, $webPath, $gcFreq, $expiration, $font, $fingerprint) { $this->value = $value; $this->imageFolder = $imageFolder; @@ -53,6 +66,8 @@ class CaptchaGenerator { $this->gcFreq = intval($gcFreq); $this->expiration = intval($expiration); $this->font = $font; + $this->fingerprint = $fingerprint; + $this->use_fingerprint = (bool)$fingerprint; } /** @@ -80,6 +95,34 @@ class CaptchaGenerator { return $this->generate($width, $height, true); } + /** + * Returns a random number or the next number in the + * fingerprint + */ + public function rand($min, $max) + { + if (!is_array($this->fingerprint)) { + $this->fingerprint = array(); + } + + if ($this->use_fingerprint) { + $value = current($this->fingerprint); + next($this->fingerprint); + } else { + $value = mt_rand($min, $max); + $this->fingerprint[] = $value; + } + return $value; + } + + /** + * Get the CAPTCHA fingerprint + */ + public function getFingerprint() + { + return $this->fingerprint; + } + /** * Deletes all images in the configured folder * that are older than 10 minutes @@ -106,17 +149,17 @@ class CaptchaGenerator { { $i = imagecreatetruecolor($width,$height); - $col = imagecolorallocate($i, mt_rand(0,110), mt_rand(0,110), mt_rand(0,110)); + $col = imagecolorallocate($i, $this->rand(0,110), $this->rand(0,110), $this->rand(0,110)); imagefill($i, 0, 0, 0xFFFFFF); // Draw random lines for ($t=0; $t<10; $t++) { - $tcol = imagecolorallocate($i, 100+mt_rand(0,150), 100+mt_rand(0,150), 100+mt_rand(0,150)); - $Xa = mt_rand(0, $width); - $Ya = mt_rand(0, $height); - $Xb = mt_rand(0, $width); - $Yb = mt_rand(0, $height); + $tcol = imagecolorallocate($i, 100+$this->rand(0,150), 100+$this->rand(0,150), 100+$this->rand(0,150)); + $Xa = $this->rand(0, $width); + $Ya = $this->rand(0, $height); + $Xb = $this->rand(0, $width); + $Yb = $this->rand(0, $height); imageline($i, $Xa, $Ya, $Xb, $Yb, $tcol); } @@ -130,11 +173,11 @@ class CaptchaGenerator { imagettftext($i, $size, 0, ($width-$txt_width)/2, ($height-$txt_height)/2+$size, $col, $font, $this->value); // Distort the image - $X = mt_rand(0, $width); - $Y = mt_rand(0, $height); - $Phase=mt_rand(0,10); - $Scale = 1.3 + mt_rand(0,10000)/30000; - $Amp=1+mt_rand(0,1000)/1000; + $X = $this->rand(0, $width); + $Y = $this->rand(0, $height); + $Phase=$this->rand(0,10); + $Scale = 1.3 + $this->rand(0,10000)/30000; + $Amp=1+$this->rand(0,1000)/1000; $out = imagecreatetruecolor($width, $height); for ($x=0; $x<$width; $x++) diff --git a/Type/CaptchaType.php b/Type/CaptchaType.php index 23c8cff..52e5f4c 100755 --- a/Type/CaptchaType.php +++ b/Type/CaptchaType.php @@ -128,7 +128,13 @@ class CaptchaType extends AbstractType public function buildView(FormView $view, FormInterface $form) { - $generator = new CaptchaGenerator($this->generateCaptchaValue(), $this->imageFolder, $this->webPath, $this->gcFreq, $this->expiration, $this->font); + $fingerprint = null; + + if ($this->session->has($this->key.'_fingerprint')) { + $fingerprint = $this->session->get($this->key.'_fingerprint'); + } + + $generator = new CaptchaGenerator($this->generateCaptchaValue(), $this->imageFolder, $this->webPath, $this->gcFreq, $this->expiration, $this->font, $fingerprint); if ($this->asFile) { $view->set('captcha_code', $generator->getFile($this->width, $this->height)); @@ -137,6 +143,10 @@ class CaptchaType extends AbstractType } $view->set('captcha_width', $this->width); $view->set('captcha_height', $this->height); + + if ($this->keepValue) { + $this->session->set($this->key.'_fingerprint', $generator->getFingerprint()); + } } public function getDefaultOptions(array $options = array()) diff --git a/Validator/CaptchaValidator.php b/Validator/CaptchaValidator.php index 47945c1..b0998e1 100644 --- a/Validator/CaptchaValidator.php +++ b/Validator/CaptchaValidator.php @@ -41,6 +41,10 @@ class CaptchaValidator implements FormValidatorInterface } $this->session->remove($this->key); + + if ($this->session->has($this->key.'_fingerprint')) { + $this->session->remove($this->key.'_fingerprint'); + } } /**