| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <?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;
- }
- }
|