Captcha.php 4.11 KB
Newer Older
1 2 3 4 5 6 7
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

crtlib committed
8
namespace yii\captcha;
9 10 11 12 13

use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Html;
use yii\helpers\Json;
Qiang Xue committed
14 15
use yii\widgets\InputWidget;

16
/**
17
 * Captcha renders a CAPTCHA image and an input field that takes user-entered verification code.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * 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
 */
34
class Captcha extends InputWidget
35 36 37 38 39 40 41
{
	/**
	 * @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';
	/**
42
	 * @var array HTML attributes to be applied to the text input field.
43 44
	 */
	public $options = array();
45 46 47 48 49 50 51 52 53 54
	/**
	 * @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}';
55 56

	/**
57
	 * Initializes the widget.
58
	 */
59
	public function init()
60
	{
61 62
		parent::init();

63 64 65
		$this->checkRequirements();

		if (!isset($this->options['id'])) {
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
			$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);
83 84
		}
		$url = Yii::$app->getUrlManager()->createUrl($this->captchaAction, array('v' => uniqid()));
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
		$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'];
100 101 102
		$view = $this->getView();
		CaptchaAsset::register($view);
		$view->registerJs("jQuery('#$id').yiiCaptcha($options);");
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
	}

	/**
	 * 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.');
	}
}