|
|
@@ -1,157 +1,158 @@
|
|
|
-<?php
|
|
|
-namespace common\helpers;
|
|
|
-
|
|
|
-use Yii;
|
|
|
-use yii\helpers\Url;
|
|
|
-use yii\web\Response;
|
|
|
-
|
|
|
-/**
|
|
|
- * 验证码扩展类
|
|
|
- * @author Leo
|
|
|
- * @copyright Copyright (c) 2016 (http://www.LeoCode.net)
|
|
|
- */
|
|
|
-class CaptchaAction extends \yii\captcha\CaptchaAction
|
|
|
-{
|
|
|
-
|
|
|
- const CAPTCHA_CODE = 'ak:captcha_code_%s';
|
|
|
-
|
|
|
- /**
|
|
|
- * GD库方式渲染
|
|
|
- * @param string $code
|
|
|
- * @return string
|
|
|
- */
|
|
|
- protected function renderImageByGD($code)
|
|
|
- {
|
|
|
- $this->fontFile = Yii::getAlias('@common/helpers/font/DroidSansMono.ttf');
|
|
|
- $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 - 1, $this->height - 1, $backColor);
|
|
|
- imagecolordeallocate($image, $backColor);
|
|
|
- $this->transparent = true;
|
|
|
- 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);
|
|
|
-
|
|
|
- // 添加彩色乱字符
|
|
|
- $chartDictionary = 'abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ2345679';
|
|
|
- for ($i = 0; $i < 50; $i++) {
|
|
|
- $chartPosition = rand(0, strlen($chartDictionary));
|
|
|
- $chartContent = substr($chartDictionary, $chartPosition, 1);
|
|
|
- $chartColor = imagecolorallocate($image, mt_rand(150, 255), mt_rand(150, 255), mt_rand(150, 255));
|
|
|
- $chartAngle = rand(-10, 10);
|
|
|
- imagettftext($image, 10, $chartAngle, rand(0, ($this->width - $this->padding * 2) - 10), rand(0, ($this->height - $this->padding * 2) - 10), $chartColor, $this->fontFile, $chartContent);
|
|
|
- }
|
|
|
-
|
|
|
- // 设置文字
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- // 验证码添加线条
|
|
|
- for ($i = 0; $i < 10; $i++) {
|
|
|
- $lineColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
|
|
- imageline($image, rand(0, 2), rand(0, ($this->width - $this->height * 2) - 2), rand(0, ($this->width - $this->padding * 2) - 2), rand(0, ($this->width - $this->height * 2) - 2), $lineColor);
|
|
|
- }
|
|
|
-
|
|
|
- // 验证码添加噪点
|
|
|
- for ($i = 0; $i < 300; $i++) {
|
|
|
- //设置点的颜色
|
|
|
- $pointColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
|
|
- imagesetpixel($image, rand(0, ($this->width - $this->padding * 2)), rand(0, ($this->width - $this->height * 2) - 10), $pointColor);
|
|
|
- }
|
|
|
-
|
|
|
- imagecolordeallocate($image, $foreColor);
|
|
|
-
|
|
|
- ob_start();
|
|
|
- imagepng($image);
|
|
|
- imagedestroy($image);
|
|
|
-
|
|
|
- return ob_get_clean();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Runs the action.
|
|
|
- */
|
|
|
- public function run()
|
|
|
- {
|
|
|
- if (Yii::$app->request->getQueryParam(self::REFRESH_GET_VAR) !== null) {
|
|
|
- // AJAX request for regenerating code
|
|
|
- $code = $this->getVerifyCode(true);
|
|
|
- Yii::$app->response->format = Response::FORMAT_JSON;
|
|
|
- return [
|
|
|
- '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' => Url::to([$this->id, 'v' => uniqid()]),
|
|
|
- ];
|
|
|
- } else {
|
|
|
- $this->setHttpHeaders();
|
|
|
- Yii::$app->response->format = Response::FORMAT_RAW;
|
|
|
- return $this->renderImage($this->getVerifyCode(true));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param bool $regenerate
|
|
|
- * @return int|mixed|string|null
|
|
|
- */
|
|
|
- public function getVerifyCode($regenerate = false)
|
|
|
- {
|
|
|
- if ($this->fixedVerifyCode !== null) {
|
|
|
- return $this->fixedVerifyCode;
|
|
|
- }
|
|
|
-// $name = $this->getSessionKey();
|
|
|
- $pageId = \Yii::$app->request->get('page_id');
|
|
|
- if( !$pageId ) {
|
|
|
- throw new \Exception('no page id');
|
|
|
- }
|
|
|
-
|
|
|
- $cacheRedis = Yii::$app->cache;
|
|
|
- $key = sprintf(self::CAPTCHA_CODE, $pageId);
|
|
|
- if( !$regenerate ) {
|
|
|
- $code = $cacheRedis->get($key);
|
|
|
- if ( $code ) return $code;
|
|
|
- }
|
|
|
-
|
|
|
- $code = $this->generateVerifyCode();
|
|
|
- $cacheRedis->set($key, $code, 300);
|
|
|
-
|
|
|
- return $code;
|
|
|
- }
|
|
|
-
|
|
|
- public function validate($input, $caseSensitive)
|
|
|
- {
|
|
|
- $code = $this->getVerifyCode();
|
|
|
- $valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0;
|
|
|
- if ( $valid ) {
|
|
|
- $this->getVerifyCode(true);
|
|
|
- }
|
|
|
-
|
|
|
- return $valid;
|
|
|
- }
|
|
|
+<?php
|
|
|
+namespace common\helpers;
|
|
|
+
|
|
|
+use Yii;
|
|
|
+use yii\helpers\Url;
|
|
|
+use yii\web\Response;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 验证码扩展类
|
|
|
+ * @author Leo
|
|
|
+ * @copyright Copyright (c) 2016 (http://www.LeoCode.net)
|
|
|
+ */
|
|
|
+class CaptchaAction extends \yii\captcha\CaptchaAction
|
|
|
+{
|
|
|
+
|
|
|
+ const CAPTCHA_CODE = 'ak:captcha_code_%s';
|
|
|
+
|
|
|
+ /**
|
|
|
+ * GD库方式渲染
|
|
|
+ * @param string $code
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ protected function renderImageByGD($code)
|
|
|
+ {
|
|
|
+ $this->fontFile = Yii::getAlias('@common/helpers/font/DroidSansMono.ttf');
|
|
|
+ $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 - 1, $this->height - 1, $backColor);
|
|
|
+ imagecolordeallocate($image, $backColor);
|
|
|
+ $this->transparent = true;
|
|
|
+ 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);
|
|
|
+
|
|
|
+ // 添加彩色乱字符
|
|
|
+ $chartDictionary = 'abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ2345679';
|
|
|
+ for ($i = 0; $i < 50; $i++) {
|
|
|
+ $chartPosition = rand(0, strlen($chartDictionary));
|
|
|
+ $chartContent = substr($chartDictionary, $chartPosition, 1);
|
|
|
+ $chartColor = imagecolorallocate($image, mt_rand(150, 255), mt_rand(150, 255), mt_rand(150, 255));
|
|
|
+ $chartAngle = rand(-10, 10);
|
|
|
+ imagettftext($image, 10, $chartAngle, rand(0, ($this->width - $this->padding * 2) - 10), rand(0, ($this->height - $this->padding * 2) - 10), $chartColor, $this->fontFile, $chartContent);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置文字
|
|
|
+ for ($i = 0; $i < $length; ++$i) {
|
|
|
+ $fontSize = (int)(rand(26, 32) * $scale * 0.8);
|
|
|
+ //$angle = rand(-10, 10);
|
|
|
+ $angle = rand(-100, 10);
|
|
|
+ $letter = $code[$i];
|
|
|
+ $box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter);
|
|
|
+ $x = $box[2] + $this->offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证码添加线条
|
|
|
+ for ($i = 0; $i < 10; $i++) {
|
|
|
+ $lineColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
|
|
+ imageline($image, rand(0, 2), rand(0, ($this->width - $this->height * 2) - 2), rand(0, ($this->width - $this->padding * 2) - 2), rand(0, ($this->width - $this->height * 2) - 2), $lineColor);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证码添加噪点
|
|
|
+ for ($i = 0; $i < 300; $i++) {
|
|
|
+ //设置点的颜色
|
|
|
+ $pointColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
|
|
+ imagesetpixel($image, rand(0, ($this->width - $this->padding * 2)), rand(0, ($this->width - $this->height * 2) - 10), $pointColor);
|
|
|
+ }
|
|
|
+
|
|
|
+ imagecolordeallocate($image, $foreColor);
|
|
|
+
|
|
|
+ ob_start();
|
|
|
+ imagepng($image);
|
|
|
+ imagedestroy($image);
|
|
|
+
|
|
|
+ return ob_get_clean();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Runs the action.
|
|
|
+ */
|
|
|
+ public function run()
|
|
|
+ {
|
|
|
+ if (Yii::$app->request->getQueryParam(self::REFRESH_GET_VAR) !== null) {
|
|
|
+ // AJAX request for regenerating code
|
|
|
+ $code = $this->getVerifyCode(true);
|
|
|
+ Yii::$app->response->format = Response::FORMAT_JSON;
|
|
|
+ return [
|
|
|
+ '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' => Url::to([$this->id, 'v' => uniqid()]),
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $this->setHttpHeaders();
|
|
|
+ Yii::$app->response->format = Response::FORMAT_RAW;
|
|
|
+ return $this->renderImage($this->getVerifyCode(true));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param bool $regenerate
|
|
|
+ * @return int|mixed|string|null
|
|
|
+ */
|
|
|
+ public function getVerifyCode($regenerate = false)
|
|
|
+ {
|
|
|
+ if ($this->fixedVerifyCode !== null) {
|
|
|
+ return $this->fixedVerifyCode;
|
|
|
+ }
|
|
|
+// $name = $this->getSessionKey();
|
|
|
+ $pageId = \Yii::$app->request->get('page_id');
|
|
|
+ if( !$pageId ) {
|
|
|
+ throw new \Exception('no page id');
|
|
|
+ }
|
|
|
+
|
|
|
+ $cacheRedis = Yii::$app->cache;
|
|
|
+ $key = sprintf(self::CAPTCHA_CODE, $pageId);
|
|
|
+ if( !$regenerate ) {
|
|
|
+ $code = $cacheRedis->get($key);
|
|
|
+ if ( $code ) return $code;
|
|
|
+ }
|
|
|
+
|
|
|
+ $code = $this->generateVerifyCode();
|
|
|
+ $cacheRedis->set($key, $code, 300);
|
|
|
+
|
|
|
+ return $code;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function validate($input, $caseSensitive)
|
|
|
+ {
|
|
|
+ $code = $this->getVerifyCode();
|
|
|
+ $valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0;
|
|
|
+ if ( $valid ) {
|
|
|
+ $this->getVerifyCode(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $valid;
|
|
|
+ }
|
|
|
}
|