thinkphp实现图像验证码

示例

在这里插入图片描述

服务类 app\common\lib\captcha

<?php
namespace app\common\lib\captcha;use think\facade\Cache;
use think\facade\Config;
use Exception;class Captcha
{private $im = null; // 验证码图片实例private $color = null; // 验证码字体颜色// 默认配置protected $config = ['length'      => 4,      // 验证码位数'fontSize'    => 25,     // 字体大小(px)'imageH'      => 0,      // 验证码高度'imageW'      => 0,      // 验证码宽度'useCurve'    => true,   // 是否画混淆曲线'useNoise'    => false,  // 是否添加杂点(已禁用)'bg'          => [243, 251, 254], // 背景颜色'fontttf'     => '',     // 字体文件路径'useZh'       => false,  // 使用中文验证码'math'        => false,  // 算术验证码'alpha'       => 0,      // 透明度(0-127)'api'         => false,  // API模式'fontPath'    => '',     // 字体文件目录'bgPath'      => '',     // 背景图片目录'expire'      => 1800,   // 验证码过期时间(s)];// 简化后的验证码字符集合(仅数字和大写字母)protected $codeSet = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';/*** 构造函数* @param array $config 配置参数*/public function __construct(array $config = []){// 合并配置参数$this->config = array_merge($this->config, Config::get('captcha', []), $config);// 设置字体路径if (empty($this->config['fontPath'])) {$this->config['fontPath'] = __DIR__ . '/ttfs/';}}/*** 生成验证码* @param string $uniqueId 前端传递的唯一标识(如时间戳)* @return string 图片二进制内容*/public function create(string $uniqueId = ''): string{// 清理过期缓存$this->clearExpiredCaptchas();// 如果未提供 uniqueId,则生成一个默认值if (empty($uniqueId)) {$uniqueId = uniqid('captcha_');}// 生成验证码文本$generator = $this->generate($uniqueId);// 计算图片宽高$this->config['imageW'] = $this->config['imageW'] ?: $this->config['length'] * $this->config['fontSize'] * 1.5;$this->config['imageH'] = $this->config['imageH'] ?: $this->config['fontSize'] * 2;// 创建图片资源$this->im = imagecreate((int)$this->config['imageW'], (int)$this->config['imageH']);// 设置背景色$bgColor = imagecolorallocate($this->im,$this->config['bg'][0],$this->config['bg'][1],$this->config['bg'][2]);imagefill($this->im, 0, 0, $bgColor);// 设置字体颜色$this->color = imagecolorallocate($this->im, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));// 添加干扰线if ($this->config['useCurve']) {$this->writeCurve();}// 绘制验证码$text = str_split($generator['value']);$space = $this->config['imageW'] / $this->config['length'];foreach ($text as $index => $char) {// 计算位置$x = $space * $index + mt_rand(5, 10);$y = $this->config['imageH'] / 2 + $this->config['fontSize'] / 2;$angle = mt_rand(-15, 15);imagettftext($this->im,(int)$this->config['fontSize'],$angle,(int)$x,(int)$y,$this->color,$this->getFont(),$char);}ob_start();imagepng($this->im);$content = ob_get_clean();imagedestroy($this->im);return $content;}/*** 验证验证码* @param string $code 用户输入的验证码* @param string $uniqueId 前端传递的唯一标识(如时间戳)* @return bool*/public function check(string $code, string $uniqueId = ''): bool{if (empty($uniqueId)) {return false;}// 从 Cache 中获取数据$cacheData = Cache::get($uniqueId);if (!$cacheData || time() - $cacheData['time'] > $this->config['expire']) {$this->removeCaptchaFromRecords($uniqueId);return false;}// 验证码校验$result = password_verify(strtoupper($code), $cacheData['key']);return $result;}/*** 生成验证码文本* @param string $uniqueId 前端传递的唯一标识(如时间戳)* @return array ['value' => 显示的文本, 'key' => 加密后的验证码]*/protected function generate(string $uniqueId): array{$bag = '';$characters = str_split($this->codeSet);for ($i = 0; $i < $this->config['length']; $i++) {$bag .= $characters[random_int(0, count($characters) - 1)];}$key = strtoupper($bag);// 使用 Bcrypt 加密验证码$hash = password_hash($key, PASSWORD_BCRYPT, ['cost' => 10]);// 将验证码信息存储到 Cache 中Cache::set($uniqueId, ['key' => $hash,'time' => time(),// 'raw' => $key // 调试用,正式环境移除], $this->config['expire']);// 记录到清理队列$this->addCaptchaToRecords($uniqueId);return ['value' => $bag, 'key' => $hash];}/*** 添加验证码记录到清理队列*/protected function addCaptchaToRecords(string $uniqueId): void{$records = Cache::get('captcha_records', []);$records[$uniqueId] = time() + $this->config['expire'];// 限制最大记录数,防止内存占用过大if (count($records) > 1000) {$records = array_slice($records, -500, null, true);}Cache::set('captcha_records', $records);}/*** 从清理队列中移除验证码记录*/protected function removeCaptchaFromRecords(string $uniqueId): void{$records = Cache::get('captcha_records', []);unset($records[$uniqueId]);Cache::set('captcha_records', $records);}/*** 清理过期的验证码缓存*/protected function clearExpiredCaptchas(): void{// 每小时清理一次$lastClear = Cache::get('last_captcha_clear', 0);if (time() - $lastClear < 3600) {return;}$records = Cache::get('captcha_records', []);$now = time();$cleaned = false;foreach ($records as $uid => $expireTime) {if ($expireTime < $now) {Cache::delete($uid);unset($records[$uid]);$cleaned = true;}}if ($cleaned) {Cache::set('captcha_records', $records);Cache::set('last_captcha_clear', time());}}/*** 获取字体文件路径* @return string* @throws Exception*/protected function getFont(): string{if (!empty($this->config['fontttf'])) {return $this->config['fontttf'];}$fonts = glob($this->config['fontPath'] . '*.ttf') +glob($this->config['fontPath'] . '*.otf');if (empty($fonts)) {throw new Exception('验证码字体文件不存在,请检查字体路径: ' . $this->config['fontPath']);}return $fonts[array_rand($fonts)];}/*** 画干扰曲线*/protected function writeCurve(): void{$px = $py = 0;// 曲线前部分$A = mt_rand(1, (int)($this->config['imageH'] / 2)); // 振幅$b = mt_rand((int)(-$this->config['imageH'] / 4), (int)($this->config['imageH'] / 4)); // Y轴偏移$f = mt_rand((int)(-$this->config['imageH'] / 4), (int)($this->config['imageH'] / 4)); // X轴偏移$T = mt_rand($this->config['imageH'], $this->config['imageW'] * 2); // 周期$w = (2 * M_PI) / $T;$px1 = 0; // 起始X坐标$px2 = mt_rand((int)($this->config['imageW'] / 2), (int)($this->config['imageW'] * 0.8)); // 结束X坐标for ($px = $px1; $px <= $px2; $px++) {if ($w != 0) {$py = $A * sin($w * $px + $f) + $b + $this->config['imageH'] / 2;$i = (int)($this->config['fontSize'] / 5);while ($i > 0) {imagesetpixel($this->im, $px + $i, $py + $i, $this->color);$i--;}}}// 曲线后部分$A = mt_rand(1, (int)($this->config['imageH'] / 2));$f = mt_rand((int)(-$this->config['imageH'] / 4), (int)($this->config['imageH'] / 4));$T = mt_rand($this->config['imageH'], $this->config['imageW'] * 2);$w = (2 * M_PI) / $T;$b = $py - $A * sin($w * $px + $f) - $this->config['imageH'] / 2;$px1 = $px2;$px2 = $this->config['imageW'];for ($px = $px1; $px <= $px2; $px++) {if ($w != 0) {$py = $A * sin($w * $px + $f) + $b + $this->config['imageH'] / 2;$i = (int)($this->config['fontSize'] / 5);while ($i > 0) {imagesetpixel($this->im, $px + $i, $py + $i, $this->color);$i--;}}}}
}

控制器调用

// 生成图形验证码public function getCaptcha(){$uid = 'captcha_' . uniqid('', true);$captcha = new \app\common\lib\captcha\Captcha();$img = $captcha->create($uid);return json(['image' => 'data:image/png;base64,'.base64_encode($img),'uid' => $uid]);}// 校验图形验证码public function checkCaptcha(){$code = input('post.code');$uid = input('post.uid');$captcha = new \app\common\lib\captcha\Captcha();$result = $captcha->check($code, $uid);return json(['success' => $result,'input_code' => $code,'uid' => $uid]);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/77554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

swift-12-Error处理、关联类型、assert、泛型_

一、错误类型 开发过程常见的错误 语法错误&#xff08;编译报错&#xff09; 逻辑错误 运行时错误&#xff08;可能会导致闪退&#xff0c;一般也叫做异常&#xff09; 2.1 通过结构体 第一步 struct MyError : Errort { var msg: String &#xff5d; 第二步 func divide(_ …

实验扩充 LED显示4*4键位值

代码功能概述 键盘扫描&#xff1a; 使用 KeyPort&#xff08;定义为 P1&#xff09;作为键盘输入端口。扫描 4x4 矩阵键盘&#xff0c;检测按键并返回按键编号&#xff08;0~15&#xff09;。 数码管显示&#xff1a; 根据按键编号&#xff0c;从 SegCode 数组中获取对应数码…

从零开始搭建CLIP模型实现基于文本的图像检索

目录 CLIP原理简介代码实现参考链接 CLIP原理简介 论文链接&#xff0c;源码链接 CLIP模型由OpenAI在2021年提出&#xff0c;利用双Decoder&#xff08;Dual Encoder&#xff09;的架构来学习图像和文本之间的对应关系&#xff0c;是多模态大模型的开创之作&#xff0c;为后续许…

熊海cms代码审计

目录 sql注入 1. admin/files/login.php 2. admin/files/columnlist.php 3. admin/files/editcolumn.php 4. admin/files/editlink.php 5. admin/files/editsoft.php 6. admin/files/editwz.php 7. admin/files/linklist.php 8. files/software.php 9. files…

[Java微服务组件]注册中心P3-Nacos中的设计模式1-观察者模式

在P1-简单注册中心实现和P2-Nacos解析中&#xff0c;我们分别实现了简单的注册中心并总结了Nacos的一些设计。 本篇继续看Nacos源码&#xff0c;了解一下Nacos中的设计模式。 目录 Nacos 观察者模式 Observer Pattern观察者模式总结 Nacos 观察者模式 Observer Pattern 模式定…

电脑 访问 github提示 找不到网页,处理方案

1、找到 本机的 host文件 例如 windows 的 一般在 C:\Windows\System32\drivers\etc\hosts 用管理员身份打开 hosts 文件 如果文件中没有 github的配置&#xff0c;需要自己手动添加上去&#xff1b; 如果有&#xff0c;则需要 检查 github.com 与 github.global.ssl.fastly.…

Linux系统中的网络管理

1.RHEL9版本中&#xff0c;使用nm进行网络配置&#xff0c;ifcfg不再是网络配置文件的主存储&#xff0c;样式仍然可用&#xff0c;但它不再是NetworkManger存储新网络配置文件的默认位置&#xff0c;RHEL以key-file格式在etc/NetworkManger/system-connections/中存储新的网络…

AI技术深度解析:从移动芯片到AIoT的全面突破

作为全球无线通信技术和半导体解决方案的重要参与者,高通始终将技术创新作为核心驱动力,在移动通信、物联网(IoT)、汽车电子、AI计算等领域占据关键地位。本文将从其核心产品线、技术突破、应用场景及未来布局四个维度,客观解析高通的技术积累与行业角色。 一、核心产品线…

使用CS Roofline Toolkit测量带宽

使用CS Roofline Toolkit测量带宽 工程下载&#xff1a;使用CS Roofline Toolkit测量带宽-案例工程文件&#xff0c;也可以按照下面的说明使用git clone下载 目录 使用CS Roofline Toolkit测量带宽0、Roofline模型理解1、CS Roofline Toolkit下载1.1、设置代理1.2、git clone下…

EAGLE代码研读+模型复现

要对代码下手了&#xff0c;加油(ง •_•)ง 作者在他们自己的设备上展现了推理的评估结果&#xff0c;受第三方评估认证&#xff0c;EAGLE为目前最快的投机方法&#xff08;虽然加速度是评估投机解码方法的主要指标&#xff0c;但其他点也值得关注。比如PLD和Lookahead无需额…

基于SFC的windows修复程序,修复绝大部分系统损坏

效果:可以自动修复大部分由系统文件损坏而导致的错误 例如:系统应用无法打开 系统窗口(例如开始菜单)无法使用 电脑蓝屏或者卡死.....文章 01技术背景 Windows自带了一个SFC命令行应用程序,可以检查大部分的系统文件错误,以及复这些文件 其中自动检查所有系统文件&#x…

liunx日志问题

一、日志定向 Linux 系统的日志配置文件&#xff08;如/etc/syslog.conf或/etc/rsyslog.conf &#xff09;中&#xff0c;用于定义系统日志的记录规则&#xff0c;决定哪些类型的日志消息会被记录到特定的日志文件中。 *.info;mail.none;authpriv.none;cron.none /va…

2.凸包优化求解

1.减而治之(Decrease and Conquer) 插入排序 典型的减而治之算法就是插入排序方法 插入排序法: 在未排序中选择一个元素&#xff0c;插入到已经排序号的序列中 将凸包也采用减而治之的方法 2.In-Convex-Polygon Test 怎么判断引入的极点存在于多边形里面还是外面&#xff1…

系统思考:危机中的转型机遇

“危机不仅是挑战&#xff0c;更是转型的机会” 每当大事发生&#xff0c;很多企业老板常常被眼前的困境压得喘不过气&#xff0c;焦虑与压力让人难以思考长远。特别是在危机面前&#xff0c;大家忙于应对眼前的风险&#xff0c;却忽略了背后隐藏的机遇。而危机&#xff0c;恰…

大模型Rag - 如何评估Rag

一.RAG流程与评估标准补充 RAG&#xff08;Retrieval-Augmented Generation&#xff09;是一种结合检索与生成的问答架构。为了确保系统效果&#xff0c;需要从以下三个角度对其评估&#xff1a; 回顾RAG流程 用户提出问题 → 系统检索相关上下文 → 基于上下文由大语言模型…

Linux RT RT RT

RT的最终目的是尽可能多的让原来系統不可抢占的部分变成可抢占&#xff0c;让高优先级的程序先跑。这里的rt引入了一个deadline的说法&#xff0c;此时的实时性是保证在最大一个时间间隔内&#xff0c;程序被执行。比如每100ms算法做一次决策。 所以此时面临着几座大山…

演员柳琦正式加入创星演员出道计划,开创演艺事业新天地

4月18日&#xff0c;演员柳琦正式加入“创星演员出道计划”&#xff0c;不仅得到参演都市爱情喜剧《和我结婚吧》角色的机会&#xff0c;还获得文旅精品网剧《醉梦灵州》的出演机会&#xff0c;自此开启全新影视之路。对表演艺术极具天赋的柳琦&#xff0c;相信未来可以凭借自身…

16.Chromium指纹浏览器开发教程之WebGPU指纹定制

WebGPU指纹概述 WebGPU是下一代的Web图形和计算API&#xff0c;旨在提供高性能的图形渲染和计算能力。它是WebGL的后继者&#xff0c;旨在利用现代GPU的强大功能&#xff0c;使得Web应用能够实现接近原生应用的图形和计算性能。而且它是一个低级别的API&#xff0c;可以直接与…

HTTP:九.WEB机器人

概念 Web机器人是能够在无需人类干预的情况下自动进行一系列Web事务处理的软件程序。人们根据这些机器人探查web站点的方式,形象的给它们取了一个饱含特色的名字,比如“爬虫”、“蜘蛛”、“蠕虫”以及“机器人”等!爬虫概述 网络爬虫(英语:web crawler),也叫网络蜘蛛(…

Vue3+TS中svg图标的使用

安装依赖 pnpm i vite-plugin-svg-icons -D配置引入 vite.config.ts ... import { createSvgIconsPlugin } from vite-plugin-svg-icons import path from node:pathconst svgIconsPlugin createSvgIconsPlugin({iconDirs: [path.resolve(process.cwd(), src/assets/icons)]…