forked from yiisoft/yii2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Captcha.php
182 lines (169 loc) · 5.65 KB
/
Captcha.php
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
172
173
174
175
176
177
178
179
180
181
182
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\captcha;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Url;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\widgets\InputWidget;
/**
* Captcha renders a CAPTCHA image and an input field that takes user-entered verification code.
*
* Captcha is used together with [[CaptchaAction]] provide [CAPTCHA](http://en.wikipedia.org/wiki/Captcha) - a way
* of preventing Website spamming.
*
* The image element rendered by Captcha will display a CAPTCHA image generated by
* an action whose route is specified by [[captchaAction]]. This action must be an instance of [[CaptchaAction]].
*
* When the user clicks on the CAPTCHA image, it will cause the CAPTCHA image
* to be refreshed with a new CAPTCHA.
*
* You may use [[\yii\captcha\CaptchaValidator]] to validate the user input matches
* the current CAPTCHA verification code.
*
* The following example shows how to use this widget with a model attribute:
*
* ```php
* echo Captcha::widget([
* 'model' => $model,
* 'attribute' => 'captcha',
* ]);
* ```
*
* The following example will use the name property instead:
*
* ```php
* echo Captcha::widget([
* 'name' => 'captcha',
* ]);
* ```
*
* You can also use this widget in an [[yii\widgets\ActiveForm|ActiveForm]] using the [[yii\widgets\ActiveField::widget()|widget()]]
* method, for example like this:
*
* ```php
* <?= $form->field($model, 'captcha')->widget(\yii\widgets\Captcha::classname(), [
* // configure additional widget properties here
* ]) ?>
* ```
*
* @author Qiang Xue <[email protected]>
* @since 2.0
*/
class Captcha extends InputWidget
{
/**
* @var string|array the route of the action that generates the CAPTCHA images.
* The action represented by this route must be an action of [[CaptchaAction]].
* Please refer to [[\yii\helpers\Url::toRoute()]] for acceptable formats.
*/
public $captchaAction = 'site/captcha';
/**
* @var array HTML attributes to be applied to the CAPTCHA image tag.
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/
public $imageOptions = [];
/**
* @var string the template for arranging the CAPTCHA image tag and the text input tag.
* In this template, the token `{image}` will be replaced with the actual image tag,
* while `{input}` will be replaced with the text input tag.
*/
public $template = '{image} {input}';
/**
* @var array the HTML attributes for the input tag.
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/
public $options = ['class' => 'form-control'];
/**
* Initializes the widget.
*/
public function init()
{
parent::init();
$this->checkRequirements();
if (!isset($this->imageOptions['id'])) {
$this->imageOptions['id'] = $this->options['id'] . '-image';
}
}
/**
* Renders the widget.
*/
public function run()
{
$this->registerClientScript();
if ($this->hasModel()) {
$input = Html::activeTextInput($this->model, $this->attribute, $this->options);
} else {
$input = Html::textInput($this->name, $this->value, $this->options);
}
$route = $this->captchaAction;
if (is_array($route)) {
$route['v'] = uniqid();
} else {
$route = [$route, 'v' => uniqid()];
}
$image = Html::img($route, $this->imageOptions);
echo strtr($this->template, [
'{input}' => $input,
'{image}' => $image,
]);
}
/**
* Registers the needed JavaScript.
*/
public function registerClientScript()
{
$options = $this->getClientOptions();
$options = empty($options) ? '' : Json::htmlEncode($options);
$id = $this->imageOptions['id'];
$view = $this->getView();
CaptchaAsset::register($view);
$view->registerJs("jQuery('#$id').yiiCaptcha($options);");
}
/**
* Returns the options for the captcha JS widget.
* @return array the options
*/
protected function getClientOptions()
{
$route = $this->captchaAction;
if (is_array($route)) {
$route[CaptchaAction::REFRESH_GET_VAR] = 1;
} else {
$route = [$route, CaptchaAction::REFRESH_GET_VAR => 1];
}
$options = [
'refreshUrl' => Url::toRoute($route),
'hashKey' => "yiiCaptcha/{$route[0]}",
];
return $options;
}
/**
* Checks if there is graphic extension available to generate CAPTCHA images.
* This method will check the existence of ImageMagick and GD extensions.
* @return string the name of the graphic extension, either "imagick" or "gd".
* @throws InvalidConfigException if neither ImageMagick nor GD is installed.
*/
public static function checkRequirements()
{
if (extension_loaded('imagick')) {
$imagick = new \Imagick();
$imagickFormats = $imagick->queryFormats('PNG');
if (in_array('PNG', $imagickFormats)) {
return 'imagick';
}
}
if (extension_loaded('gd')) {
$gdInfo = gd_info();
if (!empty($gdInfo['FreeType Support'])) {
return 'gd';
}
}
throw new InvalidConfigException('Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required.');
}
}