1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
<?php
/**
* TCaptchaValidator class file
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2014 PradoSoft
* @license http://www.pradosoft.com/license/
* @package Prado\Web\UI\WebControls
*/
namespace Prado\Web\UI\WebControls;
Prado::using('System.Web.UI.WebControls.TBaseValidator');
Prado::using('System.Web.UI.WebControls.TCaptcha');
/**
* TCaptchaValidator 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 TReCaptchaValidator}.
*
* TCaptchaValidator validates user input against a CAPTCHA represented by
* a {@link TCaptcha} control. The input control fails validation if its value
* is not the same as the token displayed in CAPTCHA. Note, if the user does
* not enter any thing, it is still considered as failing the validation.
*
* To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
* to be the ID path of the input control (usually a {@link TTextBox} control}.
* Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
* the CAPTCHA control that the user input should be compared with.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package Prado\Web\UI\WebControls
* @since 3.1.1
*/
class TCaptchaValidator extends TBaseValidator
{
/**
* Gets the name of the javascript class responsible for performing validation for this control.
* This method overrides the parent implementation.
* @return string the javascript class name
*/
protected function getClientClassName()
{
return 'Prado.WebUI.TCaptchaValidator';
}
/**
* @return string the ID path of the CAPTCHA control to validate
*/
public function getCaptchaControl()
{
return $this->getViewState('CaptchaControl','');
}
/**
* Sets the ID path of the CAPTCHA control to validate.
* The ID path is the dot-connected IDs of the controls reaching from
* the validator's naming container to the target control.
* @param string the ID path
*/
public function setCaptchaControl($value)
{
$this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
}
/**
* This method overrides the parent's implementation.
* The validation succeeds if the input control has the same value
* as the one displayed in the corresponding CAPTCHA control.
*
* @return boolean whether the validation succeeds
*/
protected function evaluateIsValid()
{
$value=$this->getValidationValue($this->getValidationTarget());
$control=$this->findCaptchaControl();
return $control->validate(trim($value));
}
/**
* @return TCaptchaControl the CAPTCHA control to be validated against
* @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
*/
protected function findCaptchaControl()
{
if(($id=$this->getCaptchaControl())==='')
throw new TConfigurationException('captchavalidator_captchacontrol_required');
else if(($control=$this->findControl($id))===null)
throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
else if(!($control instanceof TCaptcha))
throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
else
return $control;
}
/**
* Returns an array of javascript validator options.
* @return array javascript validator options.
*/
protected function getClientScriptOptions()
{
$options=parent::getClientScriptOptions();
$control=$this->findCaptchaControl();
if($control->getCaseSensitive())
{
$options['TokenHash']=$this->generateTokenHash($control->getToken());
$options['CaseSensitive']=true;
}
else
{
$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;
}
}
|