CCaptcha.php
5.24 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?php
/**
* CCaptcha class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CCaptcha renders a CAPTCHA image element.
*
* CCaptcha is used together with {@link CCaptchaAction} to provide {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA}
* - a way of preventing site spam.
*
* The image element rendered by CCaptcha will display a CAPTCHA image generated
* by an action of class {@link CCaptchaAction} belonging to the current controller.
* By default, the action ID should be 'captcha', which can be changed by setting {@link captchaAction}.
*
* CCaptcha may also render a button next to the CAPTCHA image. Clicking on the button
* will change the CAPTCHA image to be a new one in an AJAX way.
*
* If {@link clickableImage} is set true, clicking on the CAPTCHA image
* will refresh the CAPTCHA.
*
* A {@link CCaptchaValidator} may be used to validate that the user enters
* a verification code matching the code displayed in the CAPTCHA image.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web.widgets.captcha
* @since 1.0
*/
class CCaptcha extends CWidget
{
/**
* @var string the ID of the action that should provide CAPTCHA image. Defaults to 'captcha',
* meaning the 'captcha' action of the current controller. This property may also
* be in the format of 'ControllerID/ActionID'. Underneath, this property is used
* by {@link CController::createUrl} to create the URL that would serve the CAPTCHA image.
* The action has to be of {@link CCaptchaAction}.
*/
public $captchaAction='captcha';
/**
* @var boolean whether to display a button next to the CAPTCHA image. Clicking on the button
* will cause the CAPTCHA image to be changed to a new one. Defaults to true.
*/
public $showRefreshButton=true;
/**
* @var boolean whether to allow clicking on the CAPTCHA image to refresh the CAPTCHA letters.
* Defaults to false. Hint: you may want to set {@link showRefreshButton} to false if you set
* this property to be true because they serve for the same purpose.
* To enhance accessibility, you may set {@link imageOptions} to provide hints to end-users that
* the image is clickable.
*/
public $clickableImage=false;
/**
* @var string the label for the refresh button. Defaults to 'Get a new code'.
*/
public $buttonLabel;
/**
* @var string the type of the refresh button. This should be either 'link' or 'button'.
* The former refers to hyperlink button while the latter a normal push button.
* Defaults to 'link'.
*/
public $buttonType='link';
/**
* @var array HTML attributes to be applied to the rendered image element.
*/
public $imageOptions=array();
/**
* @var array HTML attributes to be applied to the rendered refresh button element.
*/
public $buttonOptions=array();
/**
* Renders the widget.
*/
public function run()
{
if(self::checkRequirements())
{
$this->renderImage();
$this->registerClientScript();
}
else
throw new CException(Yii::t('yii','GD and FreeType PHP extensions are required.'));
}
/**
* Renders the CAPTCHA image.
*/
protected function renderImage()
{
if(!isset($this->imageOptions['id']))
$this->imageOptions['id']=$this->getId();
$url=$this->getController()->createUrl($this->captchaAction,array('v'=>uniqid()));
$alt=isset($this->imageOptions['alt'])?$this->imageOptions['alt']:'';
echo CHtml::image($url,$alt,$this->imageOptions);
}
/**
* Registers the needed client scripts.
*/
public function registerClientScript()
{
$cs=Yii::app()->clientScript;
$id=$this->imageOptions['id'];
$url=$this->getController()->createUrl($this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));
$js="";
if($this->showRefreshButton)
{
// reserve a place in the registered script so that any enclosing button js code appears after the captcha js
$cs->registerScript('Yii.CCaptcha#'.$id,'// dummy');
$label=$this->buttonLabel===null?Yii::t('yii','Get a new code'):$this->buttonLabel;
$options=$this->buttonOptions;
if(isset($options['id']))
$buttonID=$options['id'];
else
$buttonID=$options['id']=$id.'_button';
if($this->buttonType==='button')
$html=CHtml::button($label, $options);
else
$html=CHtml::link($label, $url, $options);
$js="jQuery('#$id').after(".CJSON::encode($html).");";
$selector="#$buttonID";
}
if($this->clickableImage)
$selector=isset($selector) ? "$selector, #$id" : "#$id";
if(!isset($selector))
return;
$js.="
$(document).on('click', '$selector', function(){
$.ajax({
url: ".CJSON::encode($url).",
dataType: 'json',
cache: false,
success: function(data) {
$('#$id').attr('src', data['url']);
$('body').data('{$this->captchaAction}.hash', [data['hash1'], data['hash2']]);
}
});
return false;
});
";
$cs->registerScript('Yii.CCaptcha#'.$id,$js);
}
/**
* Checks if GD with FreeType support is loaded.
* @return boolean true if GD with FreeType support is loaded, otherwise false
* @since 1.1.5
*/
public static function checkRequirements()
{
if (extension_loaded('gd'))
{
$gdinfo=gd_info();
if( $gdinfo['FreeType Support'])
return true;
}
return false;
}
}