From 3d5388ff2bd01207ee608021a26037d6ae1f7383 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 3 Aug 2013 07:20:39 -0400 Subject: [PATCH] Reorganized captcha code. --- .../frontend/controllers/SiteController.php | 2 +- apps/advanced/frontend/views/site/contact.php | 2 +- apps/basic/controllers/SiteController.php | 2 +- apps/basic/views/site/contact.php | 2 +- framework/yii/assets.php | 2 +- framework/yii/assets/yii.captcha.js | 2 +- framework/yii/base/Model.php | 4 +- framework/yii/captcha/Captcha.php | 142 +++++++++ framework/yii/captcha/CaptchaAction.php | 339 +++++++++++++++++++++ framework/yii/captcha/CaptchaAsset.php | 25 ++ framework/yii/captcha/CaptchaValidator.php | 124 ++++++++ framework/yii/captcha/SpicyRice.md | 11 + framework/yii/captcha/SpicyRice.ttf | Bin 0 -> 67244 bytes framework/yii/classes.php | 16 +- framework/yii/validators/CaptchaValidator.php | 122 -------- framework/yii/validators/Validator.php | 2 +- framework/yii/web/CaptchaAction.php | 338 -------------------- framework/yii/web/SpicyRice.md | 11 - framework/yii/web/SpicyRice.ttf | Bin 67244 -> 0 bytes framework/yii/widgets/Captcha.php | 141 --------- framework/yii/widgets/CaptchaAsset.php | 24 -- tests/unit/data/base/Singer.php | 2 +- 22 files changed, 662 insertions(+), 651 deletions(-) create mode 100644 framework/yii/captcha/Captcha.php create mode 100644 framework/yii/captcha/CaptchaAction.php create mode 100644 framework/yii/captcha/CaptchaAsset.php create mode 100644 framework/yii/captcha/CaptchaValidator.php create mode 100644 framework/yii/captcha/SpicyRice.md create mode 100644 framework/yii/captcha/SpicyRice.ttf delete mode 100644 framework/yii/validators/CaptchaValidator.php delete mode 100644 framework/yii/web/CaptchaAction.php delete mode 100644 framework/yii/web/SpicyRice.md delete mode 100644 framework/yii/web/SpicyRice.ttf delete mode 100644 framework/yii/widgets/Captcha.php delete mode 100644 framework/yii/widgets/CaptchaAsset.php diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php index 285b553..c4f7f53 100644 --- a/apps/advanced/frontend/controllers/SiteController.php +++ b/apps/advanced/frontend/controllers/SiteController.php @@ -16,7 +16,7 @@ class SiteController extends Controller { return array( 'captcha' => array( - 'class' => 'yii\web\CaptchaAction', + 'class' => 'yii\captcha\CaptchaAction', ), ); } diff --git a/apps/advanced/frontend/views/site/contact.php b/apps/advanced/frontend/views/site/contact.php index 62bb9ef..3a3fb0c 100644 --- a/apps/advanced/frontend/views/site/contact.php +++ b/apps/advanced/frontend/views/site/contact.php @@ -1,7 +1,7 @@ array( - 'class' => 'yii\web\CaptchaAction', + 'class' => 'yii\captcha\CaptchaAction', 'fixedVerifyCode' => YII_ENV_DEV ? 'testme' : null, ), ); diff --git a/apps/basic/views/site/contact.php b/apps/basic/views/site/contact.php index c0e3bff..1997267 100644 --- a/apps/basic/views/site/contact.php +++ b/apps/basic/views/site/contact.php @@ -1,7 +1,7 @@ 'password2', 'on' => 'register'), * // an inline validator defined via the "authenticate()" method in the model class * array('password', 'authenticate', 'on' => 'login'), - * // a validator of class "CaptchaValidator" - * array('captcha', 'CaptchaValidator'), + * // a validator of class "DateRangeValidator" + * array('dateRange', 'DateRangeValidator'), * ); * ~~~ * diff --git a/framework/yii/captcha/Captcha.php b/framework/yii/captcha/Captcha.php new file mode 100644 index 0000000..c09399f --- /dev/null +++ b/framework/yii/captcha/Captcha.php @@ -0,0 +1,142 @@ + + * @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']; + $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() + { + $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.'); + } +} diff --git a/framework/yii/captcha/CaptchaAction.php b/framework/yii/captcha/CaptchaAction.php new file mode 100644 index 0000000..771cc02 --- /dev/null +++ b/framework/yii/captcha/CaptchaAction.php @@ -0,0 +1,339 @@ + + * @since 2.0 + */ +class CaptchaAction extends Action +{ + /** + * The name of the GET parameter indicating whether the CAPTCHA image should be regenerated. + */ + const REFRESH_GET_VAR = 'refresh'; + /** + * @var integer how many times should the same CAPTCHA be displayed. Defaults to 3. + * A value less than or equal to 0 means the test is unlimited (available since version 1.1.2). + */ + public $testLimit = 3; + /** + * @var integer the width of the generated CAPTCHA image. Defaults to 120. + */ + public $width = 120; + /** + * @var integer the height of the generated CAPTCHA image. Defaults to 50. + */ + public $height = 50; + /** + * @var integer padding around the text. Defaults to 2. + */ + public $padding = 2; + /** + * @var integer the background color. For example, 0x55FF00. + * Defaults to 0xFFFFFF, meaning white color. + */ + public $backColor = 0xFFFFFF; + /** + * @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color). + */ + public $foreColor = 0x2040A0; + /** + * @var boolean whether to use transparent background. Defaults to false. + */ + public $transparent = false; + /** + * @var integer the minimum length for randomly generated word. Defaults to 6. + */ + public $minLength = 6; + /** + * @var integer the maximum length for randomly generated word. Defaults to 7. + */ + public $maxLength = 7; + /** + * @var integer the offset between characters. Defaults to -2. You can adjust this property + * in order to decrease or increase the readability of the captcha. + **/ + public $offset = -2; + /** + * @var string the TrueType font file. This can be either a file path or path alias. + */ + public $fontFile = '@yii/captcha/SpicyRice.ttf'; + /** + * @var string the fixed verification code. When this property is set, + * [[getVerifyCode()]] will always return the value of this property. + * This is mainly used in automated tests where we want to be able to reproduce + * the same verification code each time we run the tests. + * If not set, it means the verification code will be randomly generated. + */ + public $fixedVerifyCode; + + + /** + * Initializes the action. + * @throws InvalidConfigException if the font file does not exist. + */ + public function init() + { + $this->fontFile = Yii::getAlias($this->fontFile); + if (!is_file($this->fontFile)) { + throw new InvalidConfigException("The font file does not exist: {$this->fontFile}"); + } + } + + /** + * Runs the action. + */ + public function run() + { + if (isset($_GET[self::REFRESH_GET_VAR])) { + // AJAX request for regenerating code + $code = $this->getVerifyCode(true); + /** @var \yii\web\Controller $controller */ + $controller = $this->controller; + return json_encode(array( + 'hash1' => $this->generateValidationHash($code), + 'hash2' => $this->generateValidationHash(strtolower($code)), + // we add a random 'v' parameter so that FireFox can refresh the image + // when src attribute of image tag is changed + 'url' => $controller->createUrl($this->id, array('v' => uniqid())), + )); + } else { + $this->setHttpHeaders(); + return $this->renderImage($this->getVerifyCode()); + } + } + + /** + * Generates a hash code that can be used for client side validation. + * @param string $code the CAPTCHA code + * @return string a hash code generated from the CAPTCHA code + */ + public function generateValidationHash($code) + { + for ($h = 0, $i = strlen($code) - 1; $i >= 0; --$i) { + $h += ord($code[$i]); + } + return $h; + } + + /** + * Gets the verification code. + * @param boolean $regenerate whether the verification code should be regenerated. + * @return string the verification code. + */ + public function getVerifyCode($regenerate = false) + { + if ($this->fixedVerifyCode !== null) { + return $this->fixedVerifyCode; + } + + $session = Yii::$app->getSession(); + $session->open(); + $name = $this->getSessionKey(); + if ($session[$name] === null || $regenerate) { + $session[$name] = $this->generateVerifyCode(); + $session[$name . 'count'] = 1; + } + return $session[$name]; + } + + /** + * Validates the input to see if it matches the generated code. + * @param string $input user input + * @param boolean $caseSensitive whether the comparison should be case-sensitive + * @return boolean whether the input is valid + */ + public function validate($input, $caseSensitive) + { + $code = $this->getVerifyCode(); + $valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0; + $session = Yii::$app->getSession(); + $session->open(); + $name = $this->getSessionKey() . 'count'; + $session[$name] = $session[$name] + 1; + if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) { + $this->getVerifyCode(true); + } + return $valid; + } + + /** + * Generates a new verification code. + * @return string the generated verification code + */ + protected function generateVerifyCode() + { + if ($this->minLength > $this->maxLength) { + $this->maxLength = $this->minLength; + } + if ($this->minLength < 3) { + $this->minLength = 3; + } + if ($this->maxLength > 20) { + $this->maxLength = 20; + } + $length = mt_rand($this->minLength, $this->maxLength); + + $letters = 'bcdfghjklmnpqrstvwxyz'; + $vowels = 'aeiou'; + $code = ''; + for ($i = 0; $i < $length; ++$i) { + if ($i % 2 && mt_rand(0, 10) > 2 || !($i % 2) && mt_rand(0, 10) > 9) { + $code .= $vowels[mt_rand(0, 4)]; + } else { + $code .= $letters[mt_rand(0, 20)]; + } + } + + return $code; + } + + /** + * Returns the session variable name used to store verification code. + * @return string the session variable name + */ + protected function getSessionKey() + { + return '__captcha/' . $this->getUniqueId(); + } + + /** + * Renders the CAPTCHA image. + * @param string $code the verification code + * @return string image contents + */ + protected function renderImage($code) + { + if (Captcha::checkRequirements() === 'gd') { + return $this->renderImageByGD($code); + } else { + return $this->renderImageByImagick($code); + } + } + + /** + * Renders the CAPTCHA image based on the code using GD library. + * @param string $code the verification code + * @return string image contents + */ + protected function renderImageByGD($code) + { + $image = imagecreatetruecolor($this->width, $this->height); + + $backColor = imagecolorallocate($image, + (int)($this->backColor % 0x1000000 / 0x10000), + (int)($this->backColor % 0x10000 / 0x100), + $this->backColor % 0x100); + imagefilledrectangle($image, 0, 0, $this->width, $this->height, $backColor); + imagecolordeallocate($image, $backColor); + + if ($this->transparent) { + imagecolortransparent($image, $backColor); + } + + $foreColor = imagecolorallocate($image, + (int)($this->foreColor % 0x1000000 / 0x10000), + (int)($this->foreColor % 0x10000 / 0x100), + $this->foreColor % 0x100); + + $length = strlen($code); + $box = imagettfbbox(30, 0, $this->fontFile, $code); + $w = $box[4] - $box[0] + $this->offset * ($length - 1); + $h = $box[1] - $box[5]; + $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); + $x = 10; + $y = round($this->height * 27 / 40); + for ($i = 0; $i < $length; ++$i) { + $fontSize = (int)(rand(26, 32) * $scale * 0.8); + $angle = rand(-10, 10); + $letter = $code[$i]; + $box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter); + $x = $box[2] + $this->offset; + } + + imagecolordeallocate($image, $foreColor); + + ob_start(); + imagepng($image); + imagedestroy($image); + return ob_get_clean(); + } + + /** + * Renders the CAPTCHA image based on the code using ImageMagick library. + * @param string $code the verification code + * @return \Imagick image instance. Can be used as string. In this case it will contain image contents. + */ + protected function renderImageByImagick($code) + { + $backColor = $this->transparent ? new \ImagickPixel('transparent') : new \ImagickPixel('#' . dechex($this->backColor)); + $foreColor = new \ImagickPixel('#' . dechex($this->foreColor)); + + $image = new \Imagick(); + $image->newImage($this->width, $this->height, $backColor); + + $draw = new \ImagickDraw(); + $draw->setFont($this->fontFile); + $draw->setFontSize(30); + $fontMetrics = $image->queryFontMetrics($draw, $code); + + $length = strlen($code); + $w = (int)($fontMetrics['textWidth']) - 8 + $this->offset * ($length - 1); + $h = (int)($fontMetrics['textHeight']) - 8; + $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); + $x = 10; + $y = round($this->height * 27 / 40); + for ($i = 0; $i < $length; ++$i) { + $draw = new \ImagickDraw(); + $draw->setFont($this->fontFile); + $draw->setFontSize((int)(rand(26, 32) * $scale * 0.8)); + $draw->setFillColor($foreColor); + $image->annotateImage($draw, $x, $y, rand(-10, 10), $code[$i]); + $fontMetrics = $image->queryFontMetrics($draw, $code[$i]); + $x += (int)($fontMetrics['textWidth']) + $this->offset; + } + + $image->setImageFormat('png'); + return $image; + } + + /** + * Sets the HTTP headers needed by image response. + */ + protected function setHttpHeaders() + { + Yii::$app->getResponse()->getHeaders() + ->set('Pragma', 'public') + ->set('Expires', '0') + ->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') + ->set('Content-Transfer-Encoding', 'binary') + ->set('Content-type', 'image/png'); + } +} diff --git a/framework/yii/captcha/CaptchaAsset.php b/framework/yii/captcha/CaptchaAsset.php new file mode 100644 index 0000000..50c75b7 --- /dev/null +++ b/framework/yii/captcha/CaptchaAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class CaptchaAsset extends AssetBundle +{ + public $sourcePath = '@yii/assets'; + public $js = array( + 'yii.captcha.js', + ); + public $depends = array( + 'yii\web\YiiAsset', + ); +} diff --git a/framework/yii/captcha/CaptchaValidator.php b/framework/yii/captcha/CaptchaValidator.php new file mode 100644 index 0000000..e710573 --- /dev/null +++ b/framework/yii/captcha/CaptchaValidator.php @@ -0,0 +1,124 @@ + + * @since 2.0 + */ +class CaptchaValidator extends Validator +{ + /** + * @var boolean whether to skip this validator if the input is empty. + */ + public $skipOnEmpty = false; + /** + * @var boolean whether the comparison is case sensitive. Defaults to false. + */ + public $caseSensitive = false; + /** + * @var string the route of the controller action that renders the CAPTCHA image. + */ + public $captchaAction = 'site/captcha'; + + + /** + * Initializes the validator. + */ + public function init() + { + parent::init(); + if ($this->message === null) { + $this->message = Yii::t('yii', 'The verification code is incorrect.'); + } + } + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param \yii\base\Model $object the object being validated + * @param string $attribute the attribute being validated + */ + public function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if (!$this->validateValue($value)) { + $this->addError($object, $attribute, $this->message); + } + } + + /** + * Validates the given value. + * @param mixed $value the value to be validated. + * @return boolean whether the value is valid. + */ + public function validateValue($value) + { + $captcha = $this->getCaptchaAction(); + return !is_array($value) && $captcha->validate($value, $this->caseSensitive); + } + + /** + * Returns the CAPTCHA action object. + * @throws InvalidConfigException + * @return \yii\captcha\CaptchaAction the action object + */ + public function getCaptchaAction() + { + $ca = Yii::$app->createController($this->captchaAction); + if ($ca !== false) { + /** @var \yii\base\Controller $controller */ + list($controller, $actionID) = $ca; + $action = $controller->createAction($actionID); + if ($action !== null) { + return $action; + } + } + throw new InvalidConfigException('Invalid CAPTCHA action ID: ' . $this->captchaAction); + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param \yii\base\Model $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @param \yii\base\View $view the view object that is going to be used to render views or view files + * containing a model form with this validator applied. + * @return string the client-side validation script. + */ + public function clientValidateAttribute($object, $attribute, $view) + { + $captcha = $this->getCaptchaAction(); + $code = $captcha->getVerifyCode(false); + $hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code)); + $options = array( + 'hash' => $hash, + 'hashKey' => 'yiiCaptcha/' . $this->captchaAction, + 'caseSensitive' => $this->caseSensitive, + 'message' => Html::encode(strtr($this->message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + '{value}' => $object->$attribute, + ))), + ); + if ($this->skipOnEmpty) { + $options['skipOnEmpty'] = 1; + } + + ValidationAsset::register($view); + return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');'; + } +} diff --git a/framework/yii/captcha/SpicyRice.md b/framework/yii/captcha/SpicyRice.md new file mode 100644 index 0000000..7049bd1 --- /dev/null +++ b/framework/yii/captcha/SpicyRice.md @@ -0,0 +1,11 @@ +## Spicy Rice font + +* **Author:** Brian J. Bonislawsky, Astigmatic (AOETI, Astigmatic One Eye Typographic Institute) +* **License:** SIL Open Font License (OFL), version 1.1, [notes and FAQ](http://scripts.sil.org/OFL) + +## Links + +* [Astigmatic](http://www.astigmatic.com/) +* [Google WebFonts](http://www.google.com/webfonts/specimen/Spicy+Rice) +* [fontsquirrel.com](http://www.fontsquirrel.com/fonts/spicy-rice) +* [fontspace.com](http://www.fontspace.com/astigmatic-one-eye-typographic-institute/spicy-rice) diff --git a/framework/yii/captcha/SpicyRice.ttf b/framework/yii/captcha/SpicyRice.ttf new file mode 100644 index 0000000000000000000000000000000000000000..638436cd38eab22a9e9d1a3d160a4542ec73f955 GIT binary patch literal 67244 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 W)Br(I?aL1N YII_PATH . '/caching/WinCache.php', 'yii\caching\XCache' => YII_PATH . '/caching/XCache.php', 'yii\caching\ZendDataCache' => YII_PATH . '/caching/ZendDataCache.php', + 'yii\captcha\Captcha' => YII_PATH . '/captcha/Captcha.php', + 'yii\captcha\CaptchaAction' => YII_PATH . '/captcha/CaptchaAction.php', + 'yii\captcha\CaptchaAsset' => YII_PATH . '/captcha/CaptchaAsset.php', + 'yii\captcha\CaptchaValidator' => YII_PATH . '/captcha/CaptchaValidator.php', 'yii\data\ActiveDataProvider' => YII_PATH . '/data/ActiveDataProvider.php', 'yii\data\ArrayDataProvider' => YII_PATH . '/data/ArrayDataProvider.php', 'yii\data\DataProvider' => YII_PATH . '/data/DataProvider.php', @@ -167,7 +171,6 @@ return array( 'yii\rbac\PhpManager' => YII_PATH . '/rbac/PhpManager.php', 'yii\requirements\YiiRequirementChecker' => YII_PATH . '/requirements/YiiRequirementChecker.php', 'yii\validators\BooleanValidator' => YII_PATH . '/validators/BooleanValidator.php', - 'yii\validators\CaptchaValidator' => YII_PATH . '/validators/CaptchaValidator.php', 'yii\validators\CompareValidator' => YII_PATH . '/validators/CompareValidator.php', 'yii\validators\DateValidator' => YII_PATH . '/validators/DateValidator.php', 'yii\validators\DefaultValueValidator' => YII_PATH . '/validators/DefaultValueValidator.php', @@ -193,7 +196,6 @@ return array( 'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php', 'yii\web\AssetManager' => YII_PATH . '/web/AssetManager.php', 'yii\web\CacheSession' => YII_PATH . '/web/CacheSession.php', - 'yii\web\CaptchaAction' => YII_PATH . '/web/CaptchaAction.php', 'yii\web\Controller' => YII_PATH . '/web/Controller.php', 'yii\web\Cookie' => YII_PATH . '/web/Cookie.php', 'yii\web\CookieCollection' => YII_PATH . '/web/CookieCollection.php', @@ -225,14 +227,18 @@ return array( 'yii\widgets\ActiveFormAsset' => YII_PATH . '/widgets/ActiveFormAsset.php', 'yii\widgets\Block' => YII_PATH . '/widgets/Block.php', 'yii\widgets\Breadcrumbs' => YII_PATH . '/widgets/Breadcrumbs.php', - 'yii\widgets\Captcha' => YII_PATH . '/widgets/Captcha.php', - 'yii\widgets\CaptchaAsset' => YII_PATH . '/widgets/CaptchaAsset.php', 'yii\widgets\ContentDecorator' => YII_PATH . '/widgets/ContentDecorator.php', 'yii\widgets\DetailView' => YII_PATH . '/widgets/DetailView.php', 'yii\widgets\FragmentCache' => YII_PATH . '/widgets/FragmentCache.php', + 'yii\widgets\grid\CheckboxColumn' => YII_PATH . '/widgets/grid/CheckboxColumn.php', + 'yii\widgets\grid\Column' => YII_PATH . '/widgets/grid/Column.php', + 'yii\widgets\grid\DataColumn' => YII_PATH . '/widgets/grid/DataColumn.php', + 'yii\widgets\GridView' => YII_PATH . '/widgets/GridView.php', 'yii\widgets\InputWidget' => YII_PATH . '/widgets/InputWidget.php', 'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php', - 'yii\widgets\ListPager' => YII_PATH . '/widgets/ListPager.php', + 'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php', + 'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php', + 'yii\widgets\ListViewBase' => YII_PATH . '/widgets/ListViewBase.php', 'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php', 'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php', 'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php', diff --git a/framework/yii/validators/CaptchaValidator.php b/framework/yii/validators/CaptchaValidator.php deleted file mode 100644 index 2a16f57..0000000 --- a/framework/yii/validators/CaptchaValidator.php +++ /dev/null @@ -1,122 +0,0 @@ - - * @since 2.0 - */ -class CaptchaValidator extends Validator -{ - /** - * @var boolean whether to skip this validator if the input is empty. - */ - public $skipOnEmpty = false; - /** - * @var boolean whether the comparison is case sensitive. Defaults to false. - */ - public $caseSensitive = false; - /** - * @var string the route of the controller action that renders the CAPTCHA image. - */ - public $captchaAction = 'site/captcha'; - - - /** - * Initializes the validator. - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', 'The verification code is incorrect.'); - } - } - - /** - * Validates the attribute of the object. - * If there is any error, the error message is added to the object. - * @param \yii\base\Model $object the object being validated - * @param string $attribute the attribute being validated - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - if (!$this->validateValue($value)) { - $this->addError($object, $attribute, $this->message); - } - } - - /** - * Validates the given value. - * @param mixed $value the value to be validated. - * @return boolean whether the value is valid. - */ - public function validateValue($value) - { - $captcha = $this->getCaptchaAction(); - return !is_array($value) && $captcha->validate($value, $this->caseSensitive); - } - - /** - * Returns the CAPTCHA action object. - * @throws InvalidConfigException - * @return \yii\web\CaptchaAction the action object - */ - public function getCaptchaAction() - { - $ca = Yii::$app->createController($this->captchaAction); - if ($ca !== false) { - /** @var \yii\base\Controller $controller */ - list($controller, $actionID) = $ca; - $action = $controller->createAction($actionID); - if ($action !== null) { - return $action; - } - } - throw new InvalidConfigException('Invalid CAPTCHA action ID: ' . $this->captchaAction); - } - - /** - * Returns the JavaScript needed for performing client-side validation. - * @param \yii\base\Model $object the data object being validated - * @param string $attribute the name of the attribute to be validated. - * @param \yii\base\View $view the view object that is going to be used to render views or view files - * containing a model form with this validator applied. - * @return string the client-side validation script. - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $captcha = $this->getCaptchaAction(); - $code = $captcha->getVerifyCode(false); - $hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code)); - $options = array( - 'hash' => $hash, - 'hashKey' => 'yiiCaptcha/' . $this->captchaAction, - 'caseSensitive' => $this->caseSensitive, - 'message' => Html::encode(strtr($this->message, array( - '{attribute}' => $object->getAttributeLabel($attribute), - '{value}' => $object->$attribute, - ))), - ); - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php index fe31936..c519706 100644 --- a/framework/yii/validators/Validator.php +++ b/framework/yii/validators/Validator.php @@ -49,7 +49,7 @@ abstract class Validator extends Component */ public static $builtInValidators = array( 'boolean' => 'yii\validators\BooleanValidator', - 'captcha' => 'yii\validators\CaptchaValidator', + 'captcha' => 'yii\captcha\CaptchaValidator', 'compare' => 'yii\validators\CompareValidator', 'date' => 'yii\validators\DateValidator', 'default' => 'yii\validators\DefaultValueValidator', diff --git a/framework/yii/web/CaptchaAction.php b/framework/yii/web/CaptchaAction.php deleted file mode 100644 index fef44fd..0000000 --- a/framework/yii/web/CaptchaAction.php +++ /dev/null @@ -1,338 +0,0 @@ - - * @since 2.0 - */ -class CaptchaAction extends Action -{ - /** - * The name of the GET parameter indicating whether the CAPTCHA image should be regenerated. - */ - const REFRESH_GET_VAR = 'refresh'; - /** - * @var integer how many times should the same CAPTCHA be displayed. Defaults to 3. - * A value less than or equal to 0 means the test is unlimited (available since version 1.1.2). - */ - public $testLimit = 3; - /** - * @var integer the width of the generated CAPTCHA image. Defaults to 120. - */ - public $width = 120; - /** - * @var integer the height of the generated CAPTCHA image. Defaults to 50. - */ - public $height = 50; - /** - * @var integer padding around the text. Defaults to 2. - */ - public $padding = 2; - /** - * @var integer the background color. For example, 0x55FF00. - * Defaults to 0xFFFFFF, meaning white color. - */ - public $backColor = 0xFFFFFF; - /** - * @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color). - */ - public $foreColor = 0x2040A0; - /** - * @var boolean whether to use transparent background. Defaults to false. - */ - public $transparent = false; - /** - * @var integer the minimum length for randomly generated word. Defaults to 6. - */ - public $minLength = 6; - /** - * @var integer the maximum length for randomly generated word. Defaults to 7. - */ - public $maxLength = 7; - /** - * @var integer the offset between characters. Defaults to -2. You can adjust this property - * in order to decrease or increase the readability of the captcha. - **/ - public $offset = -2; - /** - * @var string the TrueType font file. This can be either a file path or path alias. - */ - public $fontFile = '@yii/web/SpicyRice.ttf'; - /** - * @var string the fixed verification code. When this property is set, - * [[getVerifyCode()]] will always return the value of this property. - * This is mainly used in automated tests where we want to be able to reproduce - * the same verification code each time we run the tests. - * If not set, it means the verification code will be randomly generated. - */ - public $fixedVerifyCode; - - - /** - * Initializes the action. - * @throws InvalidConfigException if the font file does not exist. - */ - public function init() - { - $this->fontFile = Yii::getAlias($this->fontFile); - if (!is_file($this->fontFile)) { - throw new InvalidConfigException("The font file does not exist: {$this->fontFile}"); - } - } - - /** - * Runs the action. - */ - public function run() - { - if (isset($_GET[self::REFRESH_GET_VAR])) { - // AJAX request for regenerating code - $code = $this->getVerifyCode(true); - return json_encode(array( - 'hash1' => $this->generateValidationHash($code), - 'hash2' => $this->generateValidationHash(strtolower($code)), - // we add a random 'v' parameter so that FireFox can refresh the image - // when src attribute of image tag is changed - 'url' => $this->controller->createUrl($this->id, array('v' => uniqid())), - )); - } else { - $this->setHttpHeaders(); - return $this->renderImage($this->getVerifyCode()); - } - } - - /** - * Generates a hash code that can be used for client side validation. - * @param string $code the CAPTCHA code - * @return string a hash code generated from the CAPTCHA code - */ - public function generateValidationHash($code) - { - for ($h = 0, $i = strlen($code) - 1; $i >= 0; --$i) { - $h += ord($code[$i]); - } - return $h; - } - - /** - * Gets the verification code. - * @param boolean $regenerate whether the verification code should be regenerated. - * @return string the verification code. - */ - public function getVerifyCode($regenerate = false) - { - if ($this->fixedVerifyCode !== null) { - return $this->fixedVerifyCode; - } - - $session = Yii::$app->session; - $session->open(); - $name = $this->getSessionKey(); - if ($session[$name] === null || $regenerate) { - $session[$name] = $this->generateVerifyCode(); - $session[$name . 'count'] = 1; - } - return $session[$name]; - } - - /** - * Validates the input to see if it matches the generated code. - * @param string $input user input - * @param boolean $caseSensitive whether the comparison should be case-sensitive - * @return boolean whether the input is valid - */ - public function validate($input, $caseSensitive) - { - $code = $this->getVerifyCode(); - $valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0; - $session = Yii::$app->getSession(); - $session->open(); - $name = $this->getSessionKey() . 'count'; - $session[$name] = $session[$name] + 1; - if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) { - $this->getVerifyCode(true); - } - return $valid; - } - - /** - * Generates a new verification code. - * @return string the generated verification code - */ - protected function generateVerifyCode() - { - if ($this->minLength > $this->maxLength) { - $this->maxLength = $this->minLength; - } - if ($this->minLength < 3) { - $this->minLength = 3; - } - if ($this->maxLength > 20) { - $this->maxLength = 20; - } - $length = mt_rand($this->minLength, $this->maxLength); - - $letters = 'bcdfghjklmnpqrstvwxyz'; - $vowels = 'aeiou'; - $code = ''; - for ($i = 0; $i < $length; ++$i) { - if ($i % 2 && mt_rand(0, 10) > 2 || !($i % 2) && mt_rand(0, 10) > 9) { - $code .= $vowels[mt_rand(0, 4)]; - } else { - $code .= $letters[mt_rand(0, 20)]; - } - } - - return $code; - } - - /** - * Returns the session variable name used to store verification code. - * @return string the session variable name - */ - protected function getSessionKey() - { - return '__captcha/' . $this->getUniqueId(); - } - - /** - * Renders the CAPTCHA image. - * @param string $code the verification code - * @return string image contents - */ - protected function renderImage($code) - { - if (Captcha::checkRequirements() === 'gd') { - return $this->renderImageByGD($code); - } else { - return $this->renderImageByImagick($code); - } - } - - /** - * Renders the CAPTCHA image based on the code using GD library. - * @param string $code the verification code - * @return string image contents - */ - protected function renderImageByGD($code) - { - $image = imagecreatetruecolor($this->width, $this->height); - - $backColor = imagecolorallocate($image, - (int)($this->backColor % 0x1000000 / 0x10000), - (int)($this->backColor % 0x10000 / 0x100), - $this->backColor % 0x100); - imagefilledrectangle($image, 0, 0, $this->width, $this->height, $backColor); - imagecolordeallocate($image, $backColor); - - if ($this->transparent) { - imagecolortransparent($image, $backColor); - } - - $foreColor = imagecolorallocate($image, - (int)($this->foreColor % 0x1000000 / 0x10000), - (int)($this->foreColor % 0x10000 / 0x100), - $this->foreColor % 0x100); - - $length = strlen($code); - $box = imagettfbbox(30, 0, $this->fontFile, $code); - $w = $box[4] - $box[0] + $this->offset * ($length - 1); - $h = $box[1] - $box[5]; - $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); - $x = 10; - $y = round($this->height * 27 / 40); - for ($i = 0; $i < $length; ++$i) { - $fontSize = (int)(rand(26, 32) * $scale * 0.8); - $angle = rand(-10, 10); - $letter = $code[$i]; - $box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter); - $x = $box[2] + $this->offset; - } - - imagecolordeallocate($image, $foreColor); - - ob_start(); - imagepng($image); - imagedestroy($image); - return ob_get_clean(); - } - - /** - * Renders the CAPTCHA image based on the code using ImageMagick library. - * @param string $code the verification code - * @return \Imagick image instance. Can be used as string. In this case it will contain image contents. - */ - protected function renderImageByImagick($code) - { - $backColor = $this->transparent ? new \ImagickPixel('transparent') : new \ImagickPixel('#' . dechex($this->backColor)); - $foreColor = new \ImagickPixel('#' . dechex($this->foreColor)); - - $image = new \Imagick(); - $image->newImage($this->width, $this->height, $backColor); - - $draw = new \ImagickDraw(); - $draw->setFont($this->fontFile); - $draw->setFontSize(30); - $fontMetrics = $image->queryFontMetrics($draw, $code); - - $length = strlen($code); - $w = (int)($fontMetrics['textWidth']) - 8 + $this->offset * ($length - 1); - $h = (int)($fontMetrics['textHeight']) - 8; - $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); - $x = 10; - $y = round($this->height * 27 / 40); - for ($i = 0; $i < $length; ++$i) { - $draw = new \ImagickDraw(); - $draw->setFont($this->fontFile); - $draw->setFontSize((int)(rand(26, 32) * $scale * 0.8)); - $draw->setFillColor($foreColor); - $image->annotateImage($draw, $x, $y, rand(-10, 10), $code[$i]); - $fontMetrics = $image->queryFontMetrics($draw, $code[$i]); - $x += (int)($fontMetrics['textWidth']) + $this->offset; - } - - $image->setImageFormat('png'); - return $image; - } - - /** - * Sets the HTTP headers needed by image response. - */ - protected function setHttpHeaders() - { - Yii::$app->getResponse()->getHeaders() - ->set('Pragma', 'public') - ->set('Expires', '0') - ->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') - ->set('Content-Transfer-Encoding', 'binary') - ->set('Content-type', 'image/png'); - } -} diff --git a/framework/yii/web/SpicyRice.md b/framework/yii/web/SpicyRice.md deleted file mode 100644 index 7049bd1..0000000 --- a/framework/yii/web/SpicyRice.md +++ /dev/null @@ -1,11 +0,0 @@ -## Spicy Rice font - -* **Author:** Brian J. Bonislawsky, Astigmatic (AOETI, Astigmatic One Eye Typographic Institute) -* **License:** SIL Open Font License (OFL), version 1.1, [notes and FAQ](http://scripts.sil.org/OFL) - -## Links - -* [Astigmatic](http://www.astigmatic.com/) -* [Google WebFonts](http://www.google.com/webfonts/specimen/Spicy+Rice) -* [fontsquirrel.com](http://www.fontsquirrel.com/fonts/spicy-rice) -* [fontspace.com](http://www.fontspace.com/astigmatic-one-eye-typographic-institute/spicy-rice) diff --git a/framework/yii/web/SpicyRice.ttf b/framework/yii/web/SpicyRice.ttf deleted file mode 100644 index 638436cd38eab22a9e9d1a3d160a4542ec73f955..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67244 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 W)Br(I?aL1N - * @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']; - $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() - { - $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.'); - } -} diff --git a/framework/yii/widgets/CaptchaAsset.php b/framework/yii/widgets/CaptchaAsset.php deleted file mode 100644 index 4322e8e..0000000 --- a/framework/yii/widgets/CaptchaAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class CaptchaAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = array( - 'yii.captcha.js', - ); - public $depends = array( - 'yii\web\YiiAsset', - ); -} diff --git a/tests/unit/data/base/Singer.php b/tests/unit/data/base/Singer.php index f1b91e1..5e9111d 100644 --- a/tests/unit/data/base/Singer.php +++ b/tests/unit/data/base/Singer.php @@ -15,7 +15,7 @@ class Singer extends Model return array( array('lastName', 'default', 'value' => 'Lennon'), array('lastName', 'required'), - array('underscore_style', 'yii\validators\CaptchaValidator'), + array('underscore_style', 'yii\captcha\CaptchaValidator'), ); } }