3 * TCaptchaValidator class file
5 * @author Qiang Xue <qiang.xue@gmail.com>
6 * @link http://www.pradosoft.com/
7 * @copyright Copyright © 2005-2014 PradoSoft
8 * @license http://www.pradosoft.com/license/
9 * @package System.Web.UI.WebControls
12 Prado::using('System.Web.UI.WebControls.TBaseValidator');
13 Prado::using('System.Web.UI.WebControls.TCaptcha');
16 * TCaptchaValidator class
18 * Notice: while this class is easy to use and implement, it does not provide full security.
19 * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
20 * A better alternative is provided by {@link TReCaptchaValidator}.
22 * TCaptchaValidator validates user input against a CAPTCHA represented by
23 * a {@link TCaptcha} control. The input control fails validation if its value
24 * is not the same as the token displayed in CAPTCHA. Note, if the user does
25 * not enter any thing, it is still considered as failing the validation.
27 * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
28 * to be the ID path of the input control (usually a {@link TTextBox} control}.
29 * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
30 * the CAPTCHA control that the user input should be compared with.
32 * @author Qiang Xue <qiang.xue@gmail.com>
33 * @package System.Web.UI.WebControls
36 class TCaptchaValidator extends TBaseValidator
39 * Gets the name of the javascript class responsible for performing validation for this control.
40 * This method overrides the parent implementation.
41 * @return string the javascript class name
43 protected function getClientClassName()
45 return 'Prado.WebUI.TCaptchaValidator';
49 * @return string the ID path of the CAPTCHA control to validate
51 public function getCaptchaControl()
53 return $this->getViewState('CaptchaControl','');
57 * Sets the ID path of the CAPTCHA control to validate.
58 * The ID path is the dot-connected IDs of the controls reaching from
59 * the validator's naming container to the target control.
60 * @param string the ID path
62 public function setCaptchaControl($value)
64 $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
68 * This method overrides the parent's implementation.
69 * The validation succeeds if the input control has the same value
70 * as the one displayed in the corresponding CAPTCHA control.
72 * @return boolean whether the validation succeeds
74 protected function evaluateIsValid()
76 $value=$this->getValidationValue($this->getValidationTarget());
77 $control=$this->findCaptchaControl();
78 return $control->validate(trim($value));
82 * @return TCaptchaControl the CAPTCHA control to be validated against
83 * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
85 protected function findCaptchaControl()
87 if(($id=$this->getCaptchaControl())==='')
88 throw new TConfigurationException('captchavalidator_captchacontrol_required');
89 else if(($control=$this->findControl($id))===null)
90 throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
91 else if(!($control instanceof TCaptcha))
92 throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
98 * Returns an array of javascript validator options.
99 * @return array javascript validator options.
101 protected function getClientScriptOptions()
103 $options=parent::getClientScriptOptions();
104 $control=$this->findCaptchaControl();
105 if($control->getCaseSensitive())
107 $options['TokenHash']=$this->generateTokenHash($control->getToken());
108 $options['CaseSensitive']=true;
112 $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
113 $options['CaseSensitive']=false;
118 private function generateTokenHash($token)
120 for($h=0,$i=strlen($token)-1;$i>=0;--$i)