* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2011 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.UI.WebControls
*/
Prado::using('System.Web.UI.WebControls.TImage');
/**
* TCaptcha class.
*
* Notice: while this class is easy to use and implement, it does not provide full security.
* In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
* A better alternative is provided by {@link TReCaptcha}.
*
* TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used
* to determine if the input is entered by a real user instead of some program.
*
* Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie.
*
* The token (a string consisting of alphanumeric characters) displayed is automatically
* 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. 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 63. 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
* client-side validation besides the server-side validation. By default, the token will
* remain the same during multiple postbacks. A new one can be generated by calling
* {@link regenerateToken()} manually.
*
* The following template shows a typical use of TCaptcha control:
*
*
*
*
*
*
* @author Qiang Xue
* @version $Id$
* @package System.Web.UI.WebControls
* @since 3.1.1
*/
class TCaptcha extends TImage
{
const MIN_TOKEN_LENGTH=2;
const MAX_TOKEN_LENGTH=40;
private $_privateKey;
private $_validated=false;
/**
* @return integer the theme of the token image. Defaults to 0.
*/
public function getTokenImageTheme()
{
return $this->getViewState('TokenImageTheme',0);
}
/**
* Sets the theme of the token image.
* You may test each theme to find out the one you like the most.
* Below is the explanation of the theme value:
* It is treated as a 5-bit integer. Each bit toggles a specific feature of the image.
* Bit 0 (the least significant): whether the image is opaque (1) or transparent (0).
* Bit 1: whether we should add white noise to the image (1) or not (0).
* Bit 2: whether we should add a grid to the image (1) or not (0).
* Bit 3: whether we should add some scribbles to the image (1) or not (0).
* Bit 4: whether the image background should be morphed (1) or not (0).
* Bit 5: whether the token text should cast a shadow (1) or not (0).
* @param integer the theme of the token image. It must be an integer between 0 and 63.
*/
public function setTokenImageTheme($value)
{
$value=TPropertyValue::ensureInteger($value);
if($value>=0 && $value<=63)
$this->setViewState('TokenImageTheme',$value,0);
else
throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63);
}
/**
* @return integer the font size used for displaying the token in an image. Defaults to 30.
*/
public function getTokenFontSize()
{
return $this->getViewState('TokenFontSize',30);
}
/**
* Sets the font size used for displaying the token in an image.
* This property affects the generated token image size.
* The image width is proportional to this font size.
* @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100.
*/
public function setTokenFontSize($value)
{
$value=TPropertyValue::ensureInteger($value);
if($value>=20 && $value<=100)
$this->setViewState('TokenFontSize',$value,30);
else
throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100);
}
/**
* @return integer the minimum length of the token. Defaults to 4.
*/
public function getMinTokenLength()
{
return $this->getViewState('MinTokenLength',4);
}
/**
* @param integer the minimum length of the token. It must be between 2 and 40.
*/
public function setMinTokenLength($value)
{
$length=TPropertyValue::ensureInteger($value);
if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
$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 6.
*/
public function getMaxTokenLength()
{
return $this->getViewState('MaxTokenLength',6);
}
/**
* @param integer the maximum length of the token. It must be between 2 and 40.
*/
public function setMaxTokenLength($value)
{
$length=TPropertyValue::ensureInteger($value);
if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
$this->setViewState('MaxTokenLength',$length,6);
else
throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
}
/**
* @return boolean whether the token should be treated as case-sensitive. Defaults to true.
*/
public function getCaseSensitive()
{
return $this->getViewState('CaseSensitive',true);
}
/**
* @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token.
*/
public function setCaseSensitive($value)
{
$this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true);
}
/**
* @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'.
*/
public function getTokenAlphabet()
{
return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT');
}
/**
* @param string the characters that may appear in the token. At least 2 characters must be specified.
*/
public function setTokenAlphabet($value)
{
if(strlen($value)<2)
throw new TConfigurationException('captcha_tokenalphabet_invalid');
$this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT');
}
/**
* @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