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
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\widgets;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\web\CaptchaAction;
/**
* 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\validators\CaptchaValidator]] to validate the user input matches
* the current CAPTCHA verification code.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Captcha extends InputWidget
{
/**
* @var string the route of the action that generates the CAPTCHA images.
* The action represented by this route must be an action of [[CaptchaAction]].
*/
public $captchaAction = 'site/captcha';
/**
* @var array HTML attributes to be applied to the text input field.
*/
public $options = array();
/**
* @var array HTML attributes to be applied to the CAPTCHA image tag.
*/
public $imageOptions = array();
/**
* @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}';
/**
* Initializes the widget.
*/
public function init()
{
parent::init();
$this->checkRequirements();
if (!isset($this->options['id'])) {
$this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId();
}
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);
}
$url = Yii::$app->getUrlManager()->createUrl($this->captchaAction, array('v' => uniqid()));
$image = Html::img($url, $this->imageOptions);
echo strtr($this->template, array(
'{input}' => $input,
'{image}' => $image,
));
}
/**
* Registers the needed JavaScript.
*/
public function registerClientScript()
{
$options = $this->getClientOptions();
$options = empty($options) ? '' : Json::encode($options);
$id = $this->imageOptions['id'];
$this->getView()->registerAssetBundle('yii/captcha');
$this->getView()->registerJs("jQuery('#$id').yiiCaptcha($options);");
}
/**
* Returns the options for the captcha JS widget.
* @return array the options
*/
protected function getClientOptions()
{
$options = array(
'refreshUrl' => Html::url(array($this->captchaAction, CaptchaAction::REFRESH_GET_VAR => 1)),
'hashKey' => "yiiCaptcha/{$this->captchaAction}",
);
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('GD with FreeType or ImageMagick PHP extensions are required.');
}
}