summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorxue <>2007-08-30 15:40:24 +0000
committerxue <>2007-08-30 15:40:24 +0000
commitd1875fd32e0aa7a093544b5decd0b43499424d4f (patch)
tree223c67445e9a204cabf93274061e506889a2090a /framework
parent8a6d62fbe24321bdd83afa118726f2bd14c7dfb3 (diff)
further enhanced TCaptcha.
Diffstat (limited to 'framework')
-rw-r--r--framework/Web/Javascripts/source/prado/validator/validation3.js13
-rw-r--r--framework/Web/UI/WebControls/TCaptcha.php107
-rw-r--r--framework/Web/UI/WebControls/TCaptchaValidator.php11
-rw-r--r--framework/Web/UI/WebControls/assets/captcha.php4
4 files changed, 114 insertions, 21 deletions
diff --git a/framework/Web/Javascripts/source/prado/validator/validation3.js b/framework/Web/Javascripts/source/prado/validator/validation3.js
index 3d43a5f3..62d6e718 100644
--- a/framework/Web/Javascripts/source/prado/validator/validation3.js
+++ b/framework/Web/Javascripts/source/prado/validator/validation3.js
@@ -1388,14 +1388,11 @@ Prado.WebUI.TCaptchaValidator = Class.extend(Prado.WebUI.TBaseValidator,
*/
evaluateIsValid : function()
{
- var a = this.getValidationValue();
- if (a.length <= 0)
- return false;
- var b = this.options.TokenHash;
- if (this.options.CaseSensitive)
- return(this.crc32(a) == b);
- else
- return(this.crc32(a.toUpperCase()) == b);
+ var a = this.getValidationValue();
+ var h = 0;
+ for(var i = a.length-1; i >= 0; --i)
+ h += a.charCodeAt(i);
+ return h == this.options.TokenHash;
},
crc32 : function(str)
diff --git a/framework/Web/UI/WebControls/TCaptcha.php b/framework/Web/UI/WebControls/TCaptcha.php
index bff04236..48e57b9e 100644
--- a/framework/Web/UI/WebControls/TCaptcha.php
+++ b/framework/Web/UI/WebControls/TCaptcha.php
@@ -24,12 +24,18 @@ Prado::using('System.Web.UI.WebControls.TImage');
* generated and can be configured in several ways. To specify the length of characters
* in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}.
* To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive}
- * to false. More advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
+ * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
* specifies what characters can appear in tokens.
*
+ * The validation of the token is related with two properties: {@link setTestLimit TestLimit}
+ * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can
+ * be tested with on the server side, and the latter says when a generated token will expire.
+ *
* To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme}
* to be an integer between 0 and 31. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize}
* (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.)
+ * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background
+ * of the token will be variating even though the token is the same during postbacks.
*
* Upon postback, user input can be validated by calling {@link validate()}.
* The {@link TCaptchaValidator} control can also be used to do validation, which provides
@@ -53,9 +59,10 @@ Prado::using('System.Web.UI.WebControls.TImage');
*/
class TCaptcha extends TImage
{
- const MIN_TOKEN_LENGTH=4;
+ const MIN_TOKEN_LENGTH=2;
const MAX_TOKEN_LENGTH=40;
private $_privateKey;
+ private $_validated=false;
/**
* Checks the requirements needed for using TCaptcha.
@@ -119,11 +126,11 @@ class TCaptcha extends TImage
}
/**
- * @return integer the minimum length of the token. Defaults to 5.
+ * @return integer the minimum length of the token. Defaults to 4.
*/
public function getMinTokenLength()
{
- return $this->getViewState('MinTokenLength',5);
+ return $this->getViewState('MinTokenLength',4);
}
/**
@@ -133,17 +140,17 @@ class TCaptcha extends TImage
{
$length=TPropertyValue::ensureInteger($value);
if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MinTokenLength',$length,5);
+ $this->setViewState('MinTokenLength',$length,4);
else
throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
}
/**
- * @return integer the maximum length of the token. Defaults to 8.
+ * @return integer the maximum length of the token. Defaults to 6.
*/
public function getMaxTokenLength()
{
- return $this->getViewState('MaxTokenLength',8);
+ return $this->getViewState('MaxTokenLength',6);
}
/**
@@ -153,7 +160,7 @@ class TCaptcha extends TImage
{
$length=TPropertyValue::ensureInteger($value);
if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MaxTokenLength',$length,8);
+ $this->setViewState('MaxTokenLength',$length,6);
else
throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
}
@@ -193,6 +200,65 @@ class TCaptcha extends TImage
}
/**
+ * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes).
+ */
+ public function getTokenExpiry()
+ {
+ return $this->getViewState('TokenExpiry',600);
+ }
+
+ /**
+ * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire.
+ */
+ public function setTokenExpiry($value)
+ {
+ $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600);
+ }
+
+ /**
+ * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false.
+ */
+ public function getChangingTokenBackground()
+ {
+ return $this->getViewState('ChangingTokenBackground',false);
+ }
+
+ /**
+ * @param boolean whether the background of the token image should be variated during postbacks.
+ */
+ public function setChangingTokenBackground($value)
+ {
+ $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer how many times a generated token can be tested. Defaults to 5.
+ */
+ public function getTestLimit()
+ {
+ return $this->getViewState('TestLimit',5);
+ }
+
+ /**
+ * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0.
+ */
+ public function setTestLimit($value)
+ {
+ $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5);
+ }
+
+ /**
+ * @return boolean whether the currently generated token has expired.
+ */
+ public function getIsTokenExpired()
+ {
+ if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0)
+ return $expiry+$start<time();
+ else
+ return false;
+ }
+
+ /**
* @return string the public key used for generating the token. A random one will be generated and returned if this is not set.
*/
public function getPublicKey()
@@ -266,7 +332,18 @@ class TCaptcha extends TImage
*/
public function validate($input)
{
- return $this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input));
+ $number=$this->getViewState('TestNumber',0);
+ if(!$this->_validated)
+ {
+ $this->setViewState('TestNumber',++$number);
+ $this->_validated=true;
+ }
+ if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit))
+ {
+ $this->regenerateToken();
+ return false;
+ }
+ return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input)));
}
/**
@@ -279,6 +356,8 @@ class TCaptcha extends TImage
$this->clearViewState('TokenLength');
$this->setPublicKey('');
$this->clearViewState('TokenGenerated');
+ $this->clearViewState('RandomSeed');
+ $this->clearViewState('TestNumber',0);
}
/**
@@ -288,7 +367,7 @@ class TCaptcha extends TImage
public function onPreRender($param)
{
parent::onPreRender($param);
- if(!$this->getViewState('TokenGenerated',false))
+ if(!$this->getViewState('TokenGenerated',0))
{
$manager=$this->getApplication()->getAssetManager();
$manager->publishFilePath($this->getFontFile());
@@ -296,7 +375,7 @@ class TCaptcha extends TImage
$url.='?options='.urlencode($this->getTokenImageOptions());
$this->setImageUrl($url);
- $this->setViewState('TokenGenerated',true);
+ $this->setViewState('TokenGenerated',time());
}
}
@@ -314,6 +393,12 @@ class TCaptcha extends TImage
$options['alphabet']=$this->getTokenAlphabet();
$options['fontSize']=$this->getTokenFontSize();
$options['theme']=$this->getTokenImageTheme();
+ if(($randomSeed=$this->getViewState('RandomSeed',0))===0)
+ {
+ $randomSeed=(int)(microtime()*1000000);
+ $this->setViewState('RandomSeed',$randomSeed);
+ }
+ $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed;
$str=serialize($options);
return base64_encode(md5($privateKey.$str).$str);
}
diff --git a/framework/Web/UI/WebControls/TCaptchaValidator.php b/framework/Web/UI/WebControls/TCaptchaValidator.php
index 4385bbfe..6d2c8f4c 100644
--- a/framework/Web/UI/WebControls/TCaptchaValidator.php
+++ b/framework/Web/UI/WebControls/TCaptchaValidator.php
@@ -102,16 +102,23 @@ class TCaptchaValidator extends TBaseValidator
$control=$this->findCaptchaControl();
if($control->getCaseSensitive())
{
- $options['TokenHash']=crc32($control->getToken());
+ $options['TokenHash']=$this->generateTokenHash($control->getToken());
$options['CaseSensitive']=true;
}
else
{
- $options['TokenHash']=crc32(strtoupper($control->getToken()));
+ $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
$options['CaseSensitive']=false;
}
return $options;
}
+
+ private function generateTokenHash($token)
+ {
+ for($h=0,$i=strlen($token)-1;$i>=0;--$i)
+ $h+=ord($token[$i]);
+ return $h;
+ }
}
?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/assets/captcha.php b/framework/Web/UI/WebControls/assets/captcha.php
index 3da5f035..26ed44f4 100644
--- a/framework/Web/UI/WebControls/assets/captcha.php
+++ b/framework/Web/UI/WebControls/assets/captcha.php
@@ -37,6 +37,10 @@ if(isset($_GET['options']))
$alphabet=$options['alphabet'];
$fontSize=$options['fontSize'];
$theme=$options['theme'];
+ if(($randomSeed=$options['randomSeed'])>0)
+ srand($randomSeed);
+ else
+ srand((int)(microtime()*1000000));
$token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive);
}
}