首页
关于小站
朋友
壁纸
留言
时光之书
笔顺字帖
LayUI手册
Search
1
【PHP】PHPoffice/PHPSpreadsheet读取和写入Excel
1,687 阅读
2
【Layui】控制页面元素展示隐藏
1,535 阅读
3
【Git】No tracked branch configured for branch master or the branch doesn't exist.
1,474 阅读
4
【PHP】PHP实现JWT生成和验证
1,392 阅读
5
精准检测,助力社交管理 —— 微信好友检测服务来袭!
1,294 阅读
默认分类
PHP
ThinkPHP
Laravel
面向对象
设计模式
算法
基础
网络安全
Web
HTML
CSS
JavaScript
jQuery
Layui
VUE
uni-app
Database
MySQL
Redis
RabbitMQ
Nginx
Git
Linux
Soft Ware
Windows
网赚
Go
Docker
登录
Search
标签搜索
PHP
函数
方法
类
MySQL
ThinkPHP
JavaScript
OOP
Layui
Web
Server
Docker
Linux
PHPSpreadsheet
PHPoffice
Array
设计模式
Nginx
Git
排序算法
小破孩
累计撰写
251
篇文章
累计收到
13
条评论
首页
栏目
默认分类
PHP
ThinkPHP
Laravel
面向对象
设计模式
算法
基础
网络安全
Web
HTML
CSS
JavaScript
jQuery
Layui
VUE
uni-app
Database
MySQL
Redis
RabbitMQ
Nginx
Git
Linux
Soft Ware
Windows
网赚
Go
Docker
页面
关于小站
朋友
壁纸
留言
时光之书
笔顺字帖
LayUI手册
搜索到
33
篇与
的结果
2025-07-26
【PHP】ThinkPHP8数据库迁移示例
以下是一个包含 各种字段类型、约束条件、索引和特殊配置 的ThinkPHP8数据库迁移示例(以products产品表为例),覆盖常见场景:迁移文件示例(database/migrations/20250726153000_create_products_table.php)<?php use think\migration\Migrator; use think\migration\db\Column; class CreateProductsTable extends Migrator { /** * 执行迁移(创建表结构) */ public function change() { // 创建products表,配置表级参数 $table = $this->table('products', [ 'engine' => 'InnoDB', // 数据库引擎 'charset' => 'utf8mb4', // 字符集 'collation' => 'utf8mb4_unicode_ci', // 排序规则 'comment' => '产品表(包含多种字段类型示例)', // 表注释 'auto_increment' => 1000, // 自增ID起始值(MySQL支持) ]); // 字段定义(覆盖各种场景) $table // 1. 自增主键(整数型,无符号,自增) ->addColumn('id', 'integer', [ 'identity' => true, // 自增 'unsigned' => true, // 无符号(只存正数) 'comment' => '产品ID(主键)' ]) // 2. 字符串(有限长度,非空,唯一索引) ->addColumn('sku', 'string', [ 'limit' => 50, // 长度限制 'null' => false, // 非空(默认) 'comment' => '产品SKU(唯一标识)', 'unique' => true // 唯一约束 ]) // 3. 字符串(长文本,可空,带默认值) ->addColumn('name', 'string', [ 'limit' => 255, 'null' => false, 'default' => '', // 默认空字符串 'comment' => '产品名称' ]) // 4. 文本类型(无长度限制,可空) ->addColumn('description', 'text', [ 'null' => true, // 允许为空 'comment' => '产品详细描述' ]) // 5. 小数类型(高精度,带默认值) ->addColumn('price', 'decimal', [ 'precision' => 10, // 总位数 'scale' => 2, // 小数位数 'default' => 0.00, // 默认0.00 'comment' => '产品售价' ]) // 6. 整数类型(无符号,默认值,索引) ->addColumn('stock', 'integer', [ 'unsigned' => true, // 无符号(只存正数) 'default' => 0, // 默认库存0 'comment' => '库存数量', 'index' => true // 普通索引 ]) // 7. 枚举类型(固定可选值) ->addColumn('status', 'enum', [ 'values' => ['draft', 'active', 'disabled'], // 可选值 'default' => 'draft', // 默认草稿状态 'comment' => '产品状态(draft:草稿, active:上架, disabled:下架)' ]) // 8. 布尔类型(tinyint,默认true) ->addColumn('is_recommend', 'boolean', [ 'default' => true, // 默认true(1) 'comment' => '是否推荐(1:是, 0:否)' ]) // 9. 外键关联(整数,无符号,级联操作) ->addColumn('category_id', 'integer', [ 'unsigned' => true, 'null' => false, 'comment' => '所属分类ID', 'index' => true // 普通索引 ]) // 10. JSON类型(存储复杂结构,可空) ->addColumn('tags', 'json', [ 'null' => true, 'comment' => '产品标签(JSON格式,如["新品","热卖"])' ]) // 11. 时间戳类型(自动维护) ->addTimestamps() // 自动添加 create_time 和 update_time(datetime类型) // 12. 软删除字段(自动维护删除时间) ->addSoftDelete() // 添加 delete_time 字段(软删除标识) // 13. 整数类型(排序权重,默认0) ->addColumn('sort', 'integer', [ 'default' => 0, 'comment' => '排序权重(值越大越靠前)' ]) // 添加外键约束(关联分类表) ->addForeignKey('category_id', 'categories', 'id', [ 'delete' => 'CASCADE', // 分类删除时,关联产品也删除 'update' => 'CASCADE' // 分类ID更新时,产品关联ID同步更新 ]) // 添加联合索引(名称+状态) ->addIndex(['name', 'status'], [ 'name' => 'idx_name_status' // 自定义索引名 ]) // 执行创建表 ->create(); } /** * 回滚迁移(删除表) */ public function down() { // 先删除外键约束(避免删除表失败) $this->table('products')->dropForeignKey('category_id'); // 再删除表 $this->dropTable('products'); } }关键字段配置说明字段名类型/配置核心特点id自增整数、主键无符号,自增起始值1000sku字符串、唯一约束唯一标识,非空,长度50name字符串、默认值非空,默认空字符串,用于产品名称description文本类型、可空无长度限制,允许为空(适合长文本描述)price小数(10,2)高精度价格,默认0.00stock无符号整数、索引库存数量,非负,普通索引提升查询效率status枚举类型固定可选值,默认草稿状态is_recommend布尔类型本质tinyint,默认true(1)category_id外键、级联操作关联分类表,删除/更新时级联处理tagsJSON类型存储数组/对象结构,适合非结构化数据create_time时间戳(自动维护)由addTimestamps()生成,记录创建时间delete_time软删除字段由addSoftDelete()生成,非NULL表示已删除执行迁移# 创建表 php think migrate:run # 回滚(删除表) php think migrate:rollback注意事项外键依赖:示例中category_id关联categories表,需确保categories表已存在(可先创建分类表迁移)。索引优化:根据查询场景添加索引,避免过度索引影响写入性能。软删除:addSoftDelete()会自动添加delete_time字段(datetime类型,默认NULL),适合逻辑删除。枚举值:修改枚举值需谨慎,生产环境可能需要先添加新值再迁移数据。字段注释:每个字段添加清晰注释,便于后期维护(尤其团队协作场景)。通过这个示例,可以覆盖ThinkPHP8迁移工具中绝大多数字段配置场景,实际开发中可根据需求调整。
2025年07月26日
7 阅读
0 评论
0 点赞
2025-07-26
【PHP】ThinkPHP8 数据库迁移与数据填充完全指南
ThinkPHP8 数据库迁移与数据填充完全指南(官方文档补充版)一、安装与配置1. 安装迁移扩展composer require topthink/think-migration2. 配置文件说明配置文件位于 config/database.php默认迁移表名:think_migration支持多数据库连接3. 环境要求PHP >= 8.1ThinkPHP >= 8.0建议使用 InnoDB 引擎(支持事务)二、迁移文件操作1. 创建迁移文件# 创建基础迁移文件 php think migrate:create CreateUsersTable # 创建带表名的迁移文件(自动生成基础结构) php think migrate:create AddEmailToUsersTable --table=users # 指定数据库连接 php think migrate:create CreateLogsTable --connection=log2. 迁移文件结构生成的迁移文件位于 database/migrations,示例:<?php use think\migration\Migrator; use think\migration\db\Column; class CreateUsersTable extends Migrator { /** * 执行迁移(向上操作) */ public function up() { $table = $this->table('users'); $table->addColumn('name', 'string', ['limit' => 50]) ->addColumn('email', 'string', ['limit' => 100, 'unique' => true]) ->addColumn('password', 'string', ['limit' => 100]) ->addTimestamps() // 自动添加 create_time 和 update_time 字段 ->create(); } /** * 回滚迁移(向下操作) */ public function down() { $this->dropTable('users'); } }三、常用字段类型字段类型描述示例用法integer整数类型->addColumn('age', 'integer')biginteger大整数类型->addColumn('user_id', 'biginteger')string字符串类型->addColumn('name', 'string', ['limit' => 50])text长文本类型->addColumn('content', 'text')datetime日期时间类型->addColumn('created_at', 'datetime')timestamp时间戳类型->addColumn('updated_at', 'timestamp')boolean布尔类型->addColumn('status', 'boolean', ['default' => 0])decimal高精度小数->addColumn('price', 'decimal', ['precision' => 10, 'scale' => 2])enum枚举类型->addColumn('gender', 'enum', ['values' => ['male', 'female', 'other']])四、表结构操作1. 创建表public function up() { $table = $this->table('users', [ 'engine' => 'InnoDB', 'charset' => 'utf8mb4', 'comment' => '用户表', 'collation' => 'utf8mb4_unicode_ci' ]); $table->addColumn('id', 'integer', ['identity' => true]) // 自增ID(默认主键) ->addColumn('username', 'string', ['limit' => 30]) ->addColumn('email', 'string', ['limit' => 100, 'unique' => true]) ->addColumn('password', 'string', ['limit' => 100]) ->addColumn('status', 'boolean', ['default' => 1]) ->addIndex(['username']) // 普通索引 ->addUniqueIndex(['email']) // 唯一索引 ->addTimestamps() // 自动添加 create_time 和 update_time ->addSoftDelete() // 添加 delete_time 软删除字段 ->create(); }2. 修改表添加字段:public function up() { $this->table('users') ->addColumn('phone', 'string', ['limit' => 20, 'after' => 'email']) ->update(); }修改字段:public function up() { $this->table('users') ->changeColumn('phone', 'string', ['limit' => 11, 'default' => '']) ->update(); }删除字段:public function up() { $this->table('users') ->removeColumn('phone') ->update(); }3. 添加外键约束public function up() { $this->table('posts') ->addColumn('user_id', 'integer') ->addColumn('title', 'string') ->addColumn('content', 'text') ->addForeignKey('user_id', 'users', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) ->update(); }五、执行迁移命令1. 执行所有未迁移的文件php think migrate:run2. 回滚上一次迁移php think migrate:rollback3. 回滚到指定版本php think migrate:rollback --target=20250726101500 # 指定时间戳4. 重置所有迁移(先回滚再执行)php think migrate:reset5. 刷新数据库(重置并重新执行所有迁移)php think migrate:refresh6. 查看迁移状态php think migrate:status7. 指定数据库连接php think migrate:run --connection=db_log # 指定日志数据库六、数据填充操作1. 创建数据填充文件php think seed:create Users # 创建Users表的数据填充器2. 编写数据填充逻辑<?php use think\migration\Seeder; use think\facade\Db; class Users extends Seeder { /** * 填充数据 */ public function run() { $data = []; for ($i = 1; $i <= 10; $i++) { $data[] = [ 'username' => 'user' . $i, 'email' => 'user' . $i . '@example.com', 'password' => password_hash('123456', PASSWORD_DEFAULT), 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ]; } // 使用批量插入提高性能 Db::name('users')->insertAll($data); } }3. 执行数据填充php think seed:run # 执行所有填充器 php think seed:run --seeder Users # 执行指定填充器七、高级技巧1. 使用 change() 方法(简化双向操作)public function change() { $table = $this->table('users'); // 创建表 $table->addColumn('username', 'string') ->addColumn('email', 'string') ->create(); // 修改表 $table->addColumn('phone', 'string') ->update(); }2. 使用事务public function up() { $this->getAdapter()->beginTransaction(); try { $this->table('table1')->addColumn(...)->create(); $this->table('table2')->addColumn(...)->create(); $this->getAdapter()->commit(); } catch (\Exception $e) { $this->getAdapter()->rollBack(); throw $e; } }3. 创建数据库快照php think migrate:snapshot # 创建当前数据库结构快照4. 指定迁移文件路径php think migrate:run --path=database/migrations/custom # 指定自定义路径八、最佳实践1. 命名规范迁移文件:YYYYMMDDHHMMSS_表名_操作.php(自动生成)表名:使用小写字母和下划线(如 user_info)字段名:使用小写字母和下划线(如 create_time)2. 避免复杂SQL单个迁移文件只做单一变更避免在迁移中执行数据迁移操作3. 测试迁移在开发环境充分测试使用测试数据库验证回滚功能4. 生产环境注意事项迁移前备份数据库使用 --pretend 参数预览变更避免在高峰期执行大型迁移5. 团队协作迁移文件提交到版本控制系统避免多人同时修改同一迁移文件拉取代码后先执行 php think migrate:run九、常见问题与解决方案1. 迁移文件冲突问题:多个迁移文件时间戳相近导致执行顺序异常解决方案:使用 --timestamp 参数手动指定时间戳php think migrate:create NewTable --timestamp=202507261530002. 外键约束错误问题:删除表时外键约束阻止操作解决方案:在 down() 方法中先删除外键public function down() { $this->table('posts') ->dropForeignKey('user_id') ->update(); $this->dropTable('posts'); }3. 数据填充重复问题问题:多次执行填充器导致数据重复解决方案:在填充前清空表public function run() { Db::name('users')->delete(true); // 清空表 // 填充新数据 }4. 迁移性能问题问题:大型表迁移缓慢解决方案:分批次执行数据迁移使用数据库原生工具导入大型数据避免在迁移中使用复杂查询
2025年07月26日
10 阅读
0 评论
0 点赞
2025-05-17
【ThinkPHP】创建有背景的微信小程序二维码
<?php namespace app\common\lib\wechat; use think\Exception; use think\facade\Cache; use think\facade\Request; use think\Image; use think\facade\Db; class QrCode extends Basic { // 小程序页面路径 private string $path = "pages/myCenter/invite"; // 小程序码保存路径 private string $savePath = "./storage/qrcode/"; // 二维码参数 private string $param = ""; public function __construct(string $path = "", string $field = "", string $param = "", int $width = 430) { if (!empty($path) && empty($field)) { $this->path = $path; } if (!empty($path) && !empty($field) && !empty($param)) { $this->path = "{$path}?{$field}={$param}"; } $this->param = $param; } /** * 生成小程序码并可选择合并背景图 * * @param string $backgroundPath 背景图路径 * @param int $qrWidth 二维码在背景图上的宽度位置 * @param int $qrHeight 二维码在背景图上的高度位置 * @return string 生成后的二维码URL */ public function setQrcode(string $backgroundPath = '', int $qrWidth = 160, int $qrHeight = 530): string { try { // 获取访问令牌 $accessToken = Cache::get('accesstoken'); if (empty($accessToken)) { $accessToken = (new AccessToken())->getAccesToken(); Cache::set('accesstoken', $accessToken, 7200); // 假设token有效期为2小时 } // 请求小程序码 $url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$accessToken}"; $data = [ 'path' => $this->path, 'scene' => 'type=qrcode', 'width' => 430, ]; $result = $this->curlPost($url, $data, 'POST'); if ($result === false || isset($result['errcode'])) { throw new Exception("Failed to get QR code: " . json_encode($result)); } // 保存二维码到文件 $fileName = md5($this->param); $directory = $this->savePath . date('Ymd') . '/'; if (!$this->createDirectory($directory)) { throw new Exception("目录创建失败: {$directory}"); } $filePath = "{$directory}{$fileName}.png"; if (!file_put_contents($filePath, $result)) { throw new Exception("文件写入失败: {$filePath}"); } // 生成完整URL $fullDomain = (new \app\common\lib\data\Str())->getFullDomain(); $qrcodeUrl = $fullDomain . ltrim($filePath, '.'); // 合并背景图(如果提供) if (!empty($backgroundPath)) { return $this->mergeWithBackground($backgroundPath, $filePath, $qrcodeUrl, $qrWidth, $qrHeight); } return $qrcodeUrl; } catch (Exception $e) { // 记录错误日志 error_log($e->getMessage()); return ''; } } /** * 将二维码与背景图合并 */ private function mergeWithBackground(string $backgroundPath, string $qrcodePath, string $defaultUrl, int $qrWidth, int $qrHeight): string { try { $fileName = md5(uniqid() . time()); $newImagePath = $this->savePath . date('Ymd') . "/{$fileName}.png"; $background = Image::open($backgroundPath); $background->water($qrcodePath, [$qrWidth, $qrHeight])->save($newImagePath); $imageInfo = [ 'url' => Request::domain() . substr($newImagePath, 1), 'size' => filesize($newImagePath), 'name' => $fileName, 'mime' => mime_content_type($newImagePath), 'ext' => 'png', ]; $fileData = [ 'f_uuid' => setUUID(), 'f_file' => $imageInfo['url'], 'f_location' => 0, 'f_type' => 'image', 'f_info' => serialize($imageInfo), 'f_user_uuid' => $this->request->index_user_uuid ?? '', 'f_create_time' => time(), ]; Db::name('File')->insert($fileData); return $imageInfo['url']; } catch (Exception $e) { // 记录错误日志 error_log($e->getMessage()); return $defaultUrl; } } /** * 递归创建目录 */ private function createDirectory(string $path, int $mode = 0777, bool $recursive = true): bool { if (is_dir($path)) { return true; } if (mkdir($path, $mode, $recursive)) { chmod($path, $mode); return true; } if (!is_dir(dirname($path))) { if ($this->createDirectory(dirname($path), $mode, $recursive)) { return $this->createDirectory($path, $mode, $recursive); } } return false; } /** * 发送HTTP POST请求 */ // public function curlPost($url, $data, $method = "POST") // { // $ch = curl_init(); //1.初始化 // curl_setopt($ch, CURLOPT_URL, $url); //2.请求地址 // curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);//3.请求方式 // //4.参数如下 // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//https // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');//模拟浏览器 // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // curl_setopt($ch, CURLOPT_AUTOREFERER, 1); // curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept-Encoding: gzip, deflate'));//gzip解压内容 // curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate'); // // if ($method == "POST") {//5.post方式的时候添加数据 // $data = json_encode($data); // curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // } // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // $tmpInfo = curl_exec($ch);//6.执行 // // if (curl_errno($ch)) {//7.如果出错 // return curl_error($ch); // } // curl_close($ch);//8.关闭 // return $tmpInfo; // } }
2025年05月17日
21 阅读
0 评论
0 点赞
2025-05-07
【PHP】PHP实现无限级树形分类 树形分类 如果子集的pid不是空,父级id不存在,则子集不展示
/** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/12/17 22:27 * @param $arr * @param $id * @param $pid * @return array * @Description:树形分类 如果子集的pid不是空,父级id不存在,则子集不展示 */ public function getTreeByDateDelChile($arr,$id,$pid) { $items = []; foreach($arr as $v){ $items[$v[$id]] = $v; } $tree = []; foreach($items as $k => $item){ if($item[$pid] &&!isset($items[$item[$pid]])){ unset($items[$k]); continue; } if(isset($items[$item[$pid]])){ $items[$item[$pid]]['child'][] = &$items[$k]; }else{ $tree[] = &$items[$k]; } } return $tree; } /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/9/14 16:59 * @param array $arr * @param string $children * @return array * @Description:将树形数组转换成一维数组 */ public function setManyTosingle(array $arr = [], string $children = 'child'): array { $result = []; foreach ($arr as $item) { // 先将当前节点添加到结果数组中 $newItem = $item; if (isset($newItem[$children])) { unset($newItem[$children]); } $result[] = $newItem; // 递归处理子节点 if (isset($item[$children]) && is_array($item[$children])) { $result = array_merge($result, $this->setManyTosingle($item[$children], $children)); } } return $result; }
2025年05月07日
24 阅读
0 评论
0 点赞
2025-05-06
【PHP】清空MySQL数据,索引重置
<?php // 定义排除表的常量 const EXCLUDE_TABLES = [ 'web_admin_company', 'web_admin_func', 'web_admin_role', 'web_admin_user', 'web_app_config', 'web_china_city', 'web_china_city_area', 'web_china_city_backup', 'web_company_config', 'web_shop_category', 'web_tppay', // 'web_shop_goods_tmpserver', ]; class SomeClass { public function truncateTables() { try { // 开启事务 Db::startTrans(); // 获取所有表名 $tables = Db::query('SHOW TABLES'); $tableNames = array_map('current', $tables); foreach ($tableNames as $tableName) { if (!in_array($tableName, EXCLUDE_TABLES)) { // 使用参数化查询清空表并重置索引 Db::execute("TRUNCATE TABLE `$tableName`"); echo "表 {$tableName} 已清空<br>"; } } // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); // 记录错误日志 error_log("发生错误: " . $e->getMessage()); echo "发生错误: " . $e->getMessage(); } } }
2025年05月06日
22 阅读
0 评论
0 点赞
2025-03-13
【PHP】ThinkPHP6.1 参数验证中间件
public function handle($request, \Closure $next) { try { // 获取并清理参数 $params = array_filter(array_map(function ($value) { return is_string($value) ? trim($value) : $value; }, $request->param()), function ($value) { return is_numeric($value) || !empty($value); }); unset($params['controller'], $params['function']); if (empty($params)) return $next($request); // 设置请求属性,方便后续使用 $request->checkParam = $params; // 获取应用名、控制器和操作名 $appName = app('http')->getName(); $controller = Request::instance()->controller(true); $action = Request::instance()->action(true); // 动态构建验证器路径 $controllerParts = explode('.', $controller); $validatePathParts = array_merge([$appName, 'validate'], $controllerParts); $lastKey = array_key_last($validatePathParts); $validatePathParts[$lastKey] = ucfirst((string) $validatePathParts[$lastKey]); // $validatePath = implode('\\', array_map('ucfirst', $validatePathParts)); $validatePath = 'app\\'.implode('\\', $validatePathParts); // 检查验证器是否存在及场景是否定义 if (!class_exists($validatePath) || !$this->sceneExists($validatePath, $action)) { return $next($request); } // 验证数据 $validateInstance = new $validatePath; if (!$validateInstance->scene($action)->check($params)) { throw new Exception($validateInstance->getError()); } } catch (Exception $e) { return show(100, $e->getMessage()); } return $next($request); } /** * 检查指定验证场景是否存在 * * @param string $validateClass 验证类名 * @param string $scene 场景名 * @return bool */ protected function sceneExists(string $validateClass, string $scene): bool { return (new $validateClass)->hasScene($scene); }
2025年03月13日
130 阅读
0 评论
0 点赞
2025-03-13
【PHP】发送腾讯云短信
优化空间很大,先用着,能用<?php namespace app\common\lib\sms\tencent; //缓存 use think\facade\Cache; use TencentCloud\Common\Credential; use TencentCloud\Common\Profile\ClientProfile; use TencentCloud\Common\Profile\HttpProfile; use TencentCloud\Common\Exception\TencentCloudSDKException; use TencentCloud\Sms\V20210111\SmsClient; use TencentCloud\Sms\V20210111\Models\SendSmsRequest; class Sms{ public $SecretID = "......................"; public $SecretKey = "......................."; public $SmsSdkAppId = "..........."; public $TemplateId = "........."; public $SignName = "............"; public $code; public $phone; public function __construct($phone = '', $code = '', $tempID = '') { $this->phone = $phone; $this->code = $code; if(!empty($tempID)){ $this->TemplateId = $tempID; } } public function send(){ try { //控制台 >API密钥管理页面获取 SecretID 和 SecretKey $cred = new Credential($this->SecretID, $this->SecretKey); //实例化一个http选项 [可选] $httpProfile = new HttpProfile(); $httpProfile->setEndpoint("sms.tencentcloudapi.com"); //实例化一个client选项 [可选] $clientProfile = new ClientProfile(); $clientProfile->setHttpProfile($httpProfile); /** * 实例化以sms为例的client对象, [第三个参数 可选] * * 第二个参数是地域信息,可以直接填 ap-guangzhou */ $client = new SmsClient($cred, "ap-beijing", $clientProfile); // 实例化一个sms发送短信请求对象,每个接口都会对应一个request对象。 $req = new SendSmsRequest(); //生成随机验证码 // $code = rand(11111, 99999); // $params = array( // //接收方手机号,带上+86 示例:+8613711112222 // "PhoneNumberSet" => array((string)$this->phone), // //短信应用ID:在 [短信控制台] 添加应用后生成的实际SdkAppId // "SmsSdkAppId" => (string)$this->SmsSdkAppId, // //短信签名内容:[不理解可以看文章里的截图] // "SignName" => (string)$this->SignName, // //模板ID:必须填写已审核通过的模板 // "TemplateId" => (string)$this->TemplateId, // //我的模板中有两个参数 第一个是验证码参数 第二个是有效时间 若无模板参数,则设置为空 // "TemplateParamSet" => array((string)$this->code, '10'), // //SecretID // // "SenderId" => (string)$this->SecretID // ); $params = array( "PhoneNumberSet" => array( (string)$this->phone ), "SmsSdkAppId" => (string)$this->SmsSdkAppId, "SignName" => (string)$this->SignName, "TemplateId" => (string)$this->TemplateId, "TemplateParamSet" => array( (string)$this->code), // "SenderId" => (string)$this->SecretID ); $req->fromJsonString(json_encode($params)); //发出请求,返回一个实例 $resp = $client->SendSms($req); // print_r($resp);die; //如果成功,把验证码存入缓存 //成功实例中的Code值为 Ok if ($resp->SendStatusSet[0]->Code === "Ok") { return true; // Cache::set('name', $code, 600); // return json(['msg' => "发送成功", 'code' => 200]); } } catch (TencentCloudSDKException $e) { echo $e; } } }
2025年03月13日
56 阅读
0 评论
0 点赞
2025-03-13
【PHP】打印猿&蜂打打 开放平台 完整对接
基础类<?php namespace app\common\lib\printman; use think\facade\Log; class Basic { #APPID public $AppId; #密钥 public $AppSecret; #API地址 public $ApiUrl; #打印机ID public $PrinterId; public function __construct($AppId, $AppSecret, $PrinterId) { $this->AppId = $AppId; $this->AppSecret = $AppSecret; $this->ApiUrl = "https://iot-app-prod.fengdada.cn/mk/api"; $this->PrinterId = $PrinterId; } public function encode($BizData, $nonce) { // global $AppSecret; $jsonBytes = mb_convert_encoding($BizData , 'utf-8'); $bizData = strval($jsonBytes); $sign_ori = $bizData . $nonce . $this->AppSecret; $md5_hash = md5($sign_ori, true); $sign = base64_encode($md5_hash); return $sign; } public function generate_verification_code() { $verification_code = ""; for ($i = 0; $i < 6; $i++) { $verification_code .= strval(rand(0, 9)); } return $verification_code; } public function requests_post($url, $data, $headers) { $ch = curl_init(); curl_setopt($ch, CURLOPT_CAINFO, "cacert-2023-01-10.pem"); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return $response; } public function DoMyPost($URL, $json_BizData) { $ts = round(microtime(true) * 1000); $nonce = $this->generate_verification_code(); $sign = $this->encode($json_BizData, $nonce); $data = array( "bizData" => $json_BizData, "nonce" => $nonce, "appId" => $this->AppId, "timestamp" => strval($ts) ); $headers = array( 'Content-Type: application/json', 'sign:'.$sign ); // $response = $this->requests_post($URL, json_encode($data), $headers); $response = $this->curlRequest($URL, "POST",json_encode($data),true,false, $headers); Log::write("打印机日志:".print_r($response,true),'printman'); if(empty($response)) { echo "Error: no response received"; }else{ return $response; } } // 云打印验证码 public function PrintCaptcha() { $URL = $this->ApiUrl."/print/captcha"; $BizData = array('printerId' => $this->PrinterId); $json_BizData = json_encode($BizData); return $this->DoMyPost($URL, $json_BizData); } // 云打印机绑定 public function PrintBind($VerificationCode) { $URL = $this->ApiUrl."/printer/bind"; $BizData = array('printerId' => $this->PrinterId, 'captcha' => $VerificationCode); $json_BizData = json_encode($BizData); return $this->DoMyPost($URL, $json_BizData); } // 云打印 public function CloudPrint( $ShareCode, $PrintDataList) { $URL = $this->ApiUrl."/print"; $BizData = array('printerId' => $this->PrinterId, 'shareCode' => $ShareCode, 'printData' => $PrintDataList); $json_BizData = json_encode($BizData); return $this->DoMyPost($URL, $json_BizData); } // 云打印状态查询 public function QueryPrintStatus($ShareCode) { $URL = $this->ApiUrl."/printer/status/query"; $BizData = array('printerId' => $this->PrinterId, 'shareCode' => $ShareCode); $json_BizData = json_encode($BizData); return $this->DoMyPost($URL, $json_BizData); } //云打印解绑//0标识解绑失败,1标识解绑成功 public function unbind($ShareCode){ $URL = $this->ApiUrl."/printer/unbind"; $BizData = array('printerId' => $this->PrinterId, 'shareCode' => $ShareCode); $json_BizData = json_encode($BizData); return $this->DoMyPost($URL, $json_BizData); } /** * @Author: 小破孩嫩 * @Email: 3584685883@qq.com * @Time: 2021/4/1 10:39 * @param string $url url地址 * @param string $method 请求方法,默认为 'GET',可选值为 'GET' 或 'POST' * @param mixed $data 要发送的数据,如果是 POST 请求则为数据内容,否则为 null * @param array $headers 自定义请求头信息 * @param int $timeout 超时时间,默认为 30 秒 * @param bool $verifySSL 是否验证 SSL 证书,默认为 true * @param bool $flbg 返回值是否转成数组,默认不转 * @param bool $headercontent 是否获取请求的header值内容,默认不获取 * @return array|bool|mixed|string * @Description:curl请求 */ protected function curlRequest($url, $method = 'GET', $data = null, $flbg = false, $verifySSL = true, $headers = [], $headerContent = false, $timeout = 30) { // 初始化 cURL 会话 $ch = curl_init(); // 设置要请求的 URL curl_setopt($ch, CURLOPT_URL, $url); // 设置获取的信息以字符串形式返回,而不是直接输出 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置超时时间 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 设置请求方法 if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } // 设置请求头 if (!empty($headers)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } // 设置是否验证 SSL 证书 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifySSL); // 执行 cURL 会话并获取响应 $response = curl_exec($ch); // 获取 HTTP 响应码 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 如果 cURL 执行出错 if (curl_errno($ch)) { // 输出错误信息 echo 'Curl error: ' . curl_error($ch); // 关闭 cURL 会话并返回 false curl_close($ch); return false; } // 如果 HTTP 响应码大于等于 400(表示错误) elseif ($httpCode >= 400) { // 输出错误信息 echo "HTTP error: $httpCode"; // 关闭 cURL 会话并返回 false curl_close($ch); return false; } // 处理是否获取请求头内容 if ($headerContent && $httpCode == 200) { $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $headerSize); $body = substr($response, $headerSize); curl_close($ch); return [$headers, $body]; } // 关闭 cURL 会话 curl_close($ch); // 处理是否将响应转换为数组 if ($flbg) { $response = json_decode($response, true); } // 返回响应内容 return $response; } /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2025/1/10 14:02 * @param $code * @return string * @Description:打印机错误码 */ public function errorCode($code){ $errorCodes = [ 200 => "success 成功", 500 => "sys fail 系统异常", 2001 => "sign check fail 签名失败", 2002 => "not find partner 查无合作伙伴", 2003 => "illegal access 非法访问", 3001 => "param check error 参数错误", 3002 => "please input params 请输入参数", 40001 => "please input APPID 请输入appid", 40002 => "biz exception 业务异常", 40003 => "printer xxx is offline 打印机离线", 40004 => "printer xxx is not auth 打印机未授权", 40005 => "shareCode is error 分享码错误", 40006 => "printer xxx after 5 minutes reprinting 请5分钟后重试", 40007 => "printer xxx captcha error 验证码错误", 40008 => "printer xxx captcha expired 验证码过期", 40009 => "printer xxx bind fail 绑定失败", 40023 => "lip not close 盖子未闭合", 40023 => "sticker 粘纸", 40023 => "sticker and lip not close 粘纸并且盖子未闭合", 40023 => "no page 缺纸", 40023 => "no page and lip not close 缺纸并且盖子未闭合", 40023 => "temperature too high 温度过高", 40023 => "temperature too high and lip not close 温度过高且盖子未闭合", 40023 => "temperature too high and sticker 温度过高且粘纸", 40023 => "temperature too high and lip not close and sticker 温度过高且粘纸,盖子未闭合", 40023 => "command error 指令错误" ]; return $errorCodes[$code]; } }模板<?php namespace app\common\lib\printman\template; use app\common\lib\printman\Template; class Temp1 implements Template { protected $id; public function __construct($id = "") { $this->id = $id; } /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2025/1/10 10:51 * @return string * @Description:打印模板1 */ public function temp($order = ""){ if(empty($order)){ return "没有订单信息"; } $height = ceil(self::getTempHight($order)/10+50); $i = 40; $template = ""; $template .= "SIZE 72 mm, ".$height." mm\r\n"; $template .= "CODEPAGE 437\r\n"; $template .= "DENSITY 8\r\n"; $template .= "CLS \r\n"; $template .= "CODEPAGE 936\r\n"; $template .= "DIRECTION 0\r\n"; $template .= "TEXT 220,0,\"4\",0,1,1,\""."订单详情"."\"\r\n"; //小票标题 $template .= "TEXT 220,".$i.",\"4\",0,1,1,\"".""."\"\r\n"; //换行 $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"订单编号:".$order['o_uuid']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"打印时间:".date("Y-m-d H:i:s")."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"申 请 人:".$order['o_address_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"联系方式:".$order['o_address_tel_default']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"收货地址:".mb_substr($order['o_address_info'],0,16)."\"\r\n"; if(mb_strlen($order['o_address_info']) > 16){ $template .= "TEXT 40,"; $template .= $i+=30; $template .=",\"0\",0,1,1,\" ".mb_substr($order['o_address_info'],16)."\"\r\n"; } $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"申请时间:".$order['o_create_time']."\"\r\n"; // $template .= "TEXT 40,"; // $template .= $i+=30; // $template .= ",\"0\",0,1,1,\"审核时间:".date("Y-m-d H:i:s",$order['o_pay_receipt_allow_time'])."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"配 送 员:".$order['salesmaninfo']['sm_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"配送电话:".$order['salesmaninfo']['sm_phone']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"出货仓库:".$order['warehouse_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"商品总数:".$order['goods_total_num']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"商品总价:".$order['o_real_price']."\"\r\n"; $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; $template .= "TEXT 40,"; $template .= $i+=16; $template .= ",\"0\",0,1,1,\"商品 数量 单价 金额\"\r\n"; $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; foreach ($order['order_list'] as $kk => $vv){ if(!empty($vv['oi_issendgoods'])){ $firstNamaText = "赠品:"; }else{ $firstNamaText = "商品:"; } $knum = $kk+=1; $template .= "TEXT 30,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"$knum.". mb_substr($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')',0,26)."\"\r\n"; if(mb_strlen($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')') > 26){ $template .= "TEXT 30,"; $template .= $i+=30; $template .=",\"0\",0,1,1,\" ".mb_substr($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')',26)."\"\r\n"; } $template .= "TEXT 65,"; $template .= $i+=30; if(!empty($vv['oi_issendgoods'])){ $template .=",\"0\",0,1,1,\"".$vv['oi_sku_info']['num'].'件'.' '."0.00".' '."0.00"."\"\r\n"; }else{ $template .=",\"0\",0,1,1,\"".$vv['oi_sku_info']['num'].'件'.' '.sprintf("%.2f",$vv['oi_sku_info']['sgcs_price']/$vv['oi_sku_info']['num']).' '.$vv['oi_real_price']."\"\r\n"; } } $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"数量总计:".$order['goods_total_num'].'件'."\"\r\n"; $template .= "PRINT 1,1"; $instacneStr = new \app\common\lib\data\Str(); $data = [ 'waybillPrinterData' => $instacneStr->gzipAndBase64Encode($template), 'printType' => 'tspl', 'id' => $this->id ]; return [$data]; } protected function getTempHight($order){ $i = 50; $template = ""; $template .= "SIZE 72 mm, 90 mm\r\n"; $template .= "CODEPAGE 437\r\n"; $template .= "DENSITY 8\r\n"; $template .= "CLS \r\n"; $template .= "CODEPAGE 936\r\n"; $template .= "DIRECTION 0\r\n"; $template .= "TEXT 220,0,\"4\",0,1,1,\""."订单详情"."\"\r\n"; //小票标题 $template .= "TEXT 220,".$i.",\"4\",0,1,1,\"".""."\"\r\n"; //换行 $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"订单编号:".$order['o_uuid']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"打印时间:".date("Y-m-d H:i:s")."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"申 请 人:".$order['o_address_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"联系方式:".$order['o_address_tel_default']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"收货地址:".mb_substr($order['o_address_info'],0,16)."\"\r\n"; if(mb_strlen($order['o_address_info']) > 16){ $template .= "TEXT 40,"; $template .= $i+=30; $template .=",\"0\",0,1,1,\" ".mb_substr($order['o_address_info'],16)."\"\r\n"; } $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"申请时间:".$order['o_create_time']."\"\r\n"; // if(empty($order['o_help'])){ // $template .= "TEXT 40,"; // $template .= $i+=30; // $template .= ",\"0\",0,1,1,\"审核时间:".date("Y-m-d H:i:s",$order['o_pay_receipt_allow_time'])."\"\r\n"; // } $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"配送员姓名:".$order['salesmaninfo']['sm_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"配送员电话:".$order['salesmaninfo']['sm_phone']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"出货仓库:".$order['warehouse_name']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"商品总数:".$order['goods_total_num']."\"\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"商品总价:".$order['o_real_price']."\"\r\n"; $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; $template .= "TEXT 40,"; $template .= $i+=16; $template .= ",\"0\",0,1,1,\"商品 数量 单价 金额\"\r\n"; $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; // foreach ($order as $key => $val){ foreach ($order['order_list'] as $kk => $vv){ if(!empty($vv['oi_issendgoods'])){ $firstNamaText = "赠品:"; }else{ $firstNamaText = "商品:"; } $knum = $kk+=1; $template .= "TEXT 30,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"$knum.". mb_substr($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')',0,26)."\"\r\n"; if(mb_strlen($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')') > 26){ $template .= "TEXT 30,"; $template .= $i+=30; $template .=",\"0\",0,1,1,\" ".mb_substr($firstNamaText.$vv['oi_sku_info']['goods_info']['withgoodsinfoinfo']['sg_name'].'('.$vv['oi_sku_info']['sgcs_name'].')',26)."\"\r\n"; } $template .= "TEXT 65,"; $template .= $i+=30; $template .=",\"0\",0,1,1,\"".$vv['oi_sku_info']['num'].'件'.' '.$vv['oi_sku_info']['sgcs_price'].' '.$vv['oi_sku_info']['sgcs_price']*$vv['oi_sku_info']['num']."\"\r\n"; } $template .= "BAR 20,"; $template .= $i+=28; $template .= ",720,2\r\n"; $template .= "TEXT 40,"; $template .= $i+=30; $template .= ",\"0\",0,1,1,\"数量总计:".$order['goods_total_num']."\"\r\n"; // } $template .= "PRINT 1,1"; return $i; } }
2025年03月13日
130 阅读
0 评论
1 点赞
2025-03-13
【PHP】给富文本内容的图片,视频,文件 拼接当前网址域名
/** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/11/18 15:20 * @param $text * @param $domain * @return string|string[]|null * @Description:给服务文本拼接当前网址域名 */ public function addDomainToPaths($text, $domain){ // 匹配图片路径 $text = preg_replace('/<img.*?src="([^"]+)"/i', '<img src="' . $domain . '$1"', $text); // 匹配视频路径 $text = preg_replace('/<video.*?src="([^"]+)"/i', '<video src="' . $domain . '$1"', $text); // 匹配文件路径(可根据具体文件类型的链接特征进行修改) $text = preg_replace('/<a.*?href="([^"]+)"/i', '<a href="' . $domain . '$1"', $text); return $text; }
2025年03月13日
109 阅读
0 评论
0 点赞
2025-03-13
【PHP】过滤富文本内容
封装了一个类class TextFilter { // 定义要过滤的 SQL 关键字模式 const SQL_PATTERNS = [ '/\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|AND|OR|JOIN|DROP|CREATE|ALTER|TRUNCATE|GRANT|REVOKE|SET)\b/i', '/\b(AS|LIKE|NOT|IN|BETWEEN|IS|NULL|COUNT|SUM|AVG|MIN|MAX)\b/i', '/\b(UNION|ALL|ANY|EXISTS)\b/i', '/\b(ORDER\s+BY|LIMIT)\b/i' ]; // 定义要过滤的常见函数模式 const FUNCTION_PATTERNS = [ '/\b(function\s+\w+\s*\([^)]*\))\b/i', '/\b(eval|exec|system|passthru|shell_exec|assert)\b/i' ]; // 定义要过滤的特殊字符和表达式模式 const SPECIAL_PATTERNS = [ '/\$\{.*?\}/', // 过滤类似 ${expression} 的表达式 '/@.*?;/', // 过滤以 @ 开头并以 ; 结尾的表达式 '/\b(phpinfo|var_dump)\b/i', // 过滤特定的 PHP 函数 '/<\s*(script|iframe|object|embed|applet)[^>]*>/i' // 过滤危险的脚本标签 ]; // 定义要过滤的危险属性模式 const DANGEROUS_ATTRIBUTES_PATTERNS = [ '/on\w+\s*=/i', // 过滤以 "on" 开头的事件属性 '/javascript:[^"]*"/i' // 过滤 JavaScript 协议的链接 ]; /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/10/24 13:50 * @param $text * @return string|string[]|null * @Description:过滤富文本 */ public static function filterRichText($text) { // 合并所有要过滤的模式 $allPatterns = array_merge( self::SQL_PATTERNS, self::FUNCTION_PATTERNS, self::SPECIAL_PATTERNS, self::DANGEROUS_ATTRIBUTES_PATTERNS ); // 先过滤所有匹配的模式 $filteredText = preg_replace($allPatterns, '', $text); // 保留 <img> 标签,但需要确保 src 属性是安全的 $filteredText = preg_replace_callback('/<img[^>]+>/i', [__CLASS__, 'filterImgTag'], $filteredText); // 允许表情符号和其他图标 $filteredText = preg_replace('/[\x{1F600}-\x{1F64F}]|\x{1F300}-\x{1F5FF}|\x{1F680}-\x{1F6FF}|\x{2600}-\x{26FF}|\x{2700}-\x{27BF}/u', '$0', $filteredText); // 处理可能出现的连续空格 $filteredText = preg_replace('/\s+/', ' ', $filteredText); // 去除前后的空格 $filteredText = trim($filteredText); // 转换 HTML 实体 $filteredText = htmlentities($filteredText, ENT_QUOTES, 'UTF-8'); return $filteredText; } private static function filterImgTag($matches) { $imgTag = $matches[0]; if (preg_match('/src=["\'](?<src>[^"\']+)["\']/i', $imgTag, $srcMatch)) { $src = $srcMatch['src']; // 这里可以进一步验证 src 是否是允许的 URL 或本地路径 if (filter_var($src, FILTER_VALIDATE_URL) || strpos($src, '/') === 0) { return $imgTag; } } return ''; } } // 示例调用 $text = '<script>alert("XSS")</script><img src="https://example.com/image.jpg">'; $filteredText = TextFilter::filterRichText($text); echo $filteredText; 函数 方法 /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/10/24 13:50 * @param $text * @return string|string[]|null * @Description:过滤富文本 */ public static function filterRichText($text){ // 定义要过滤的 SQL 关键字模式 $sqlPatterns = [ '/\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|AND|OR|JOIN|DROP|CREATE|ALTER|TRUNCATE|GRANT|REVOKE|SET)\b/i', '/\b(AS|LIKE|NOT|IN|BETWEEN|IS|NULL|COUNT|SUM|AVG|MIN|MAX)\b/i', '/\b(UNION|ALL|ANY|EXISTS)\b/i', '/\b(ORDER\s+BY|LIMIT)\b/i' ]; // 定义要过滤的常见函数模式 $functionPatterns = [ '/\b(function\s+\w+\s*\([^)]*\))\b/i', '/\b(eval|exec|system|passthru|shell_exec|assert)\b/i' ]; // 定义要过滤的特殊字符和表达式模式 $specialPatterns = [ '/\$\{.*?\}/', // 过滤类似 ${expression} 的表达式 '/@.*?;/', // 过滤以 @ 开头并以 ; 结尾的表达式 '/\b(phpinfo|var_dump)\b/i', // 过滤特定的 PHP 函数 '/<\s*(script|iframe|object|embed|applet)[^>]*>/i' // 过滤危险的脚本标签 ]; // 定义要过滤的危险属性模式 $dangerousAttributesPatterns = [ '/on\w+\s*=/i', // 过滤以 "on" 开头的事件属性 '/javascript:[^"]*"/i' // 过滤 JavaScript 协议的链接 ]; // 先过滤 SQL 关键字 $filteredText = preg_replace($sqlPatterns, '', $text); // 再过滤函数 $filteredText = preg_replace($functionPatterns, '', $filteredText); // 然后过滤特殊字符和表达式 $filteredText = preg_replace($specialPatterns, '', $filteredText); // 接着过滤危险的属性 $filteredText = preg_replace($dangerousAttributesPatterns, '', $filteredText); // 允许表情符号和其他图标 $filteredText = preg_replace('/[\x{1F600}-\x{1F64F}]|\x{1F300}-\x{1F5FF}|\x{1F680}-\x{1F6FF}|\x{2600}-\x{26FF}|\x{2700}-\x{27BF}/u', '$0', $filteredText); // 处理可能出现的连续空格 $filteredText = preg_replace('/\s+/', ' ', $filteredText); // 去除前后的空格 $filteredText = trim($filteredText); // 转换 HTML 实体 $filteredText = htmlentities($filteredText, ENT_QUOTES, 'UTF-8'); return $filteredText; } /** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/10/24 13:50 * @param $text * @return string|string[]|null * @Description:过滤富文本 */ function filterRichText($text) { // 合并所有要过滤的模式 $patterns = [ '/\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|AND|OR|JOIN|DROP|CREATE|ALTER|TRUNCATE|GRANT|REVOKE|SET)\b/i', '/\b(AS|LIKE|NOT|IN|BETWEEN|IS|NULL|COUNT|SUM|AVG|MIN|MAX)\b/i', '/\b(UNION|ALL|ANY|EXISTS)\b/i', '/\b(ORDER\s+BY|LIMIT)\b/i', '/\b(function\s+\w+\s*\([^)]*\))\b/i', '/\b(eval|exec|system|passthru|shell_exec|assert)\b/i', '/\$\{.*?\}/', '/@.*?;/', '/\b(phpinfo|var_dump)\b/i', '/<\s*(script|iframe|object|embed|applet)[^>]*>/i', '/on\w+\s*=/i', '/javascript:[^"]*"/i' ]; // 先过滤所有匹配的模式 $filteredText = preg_replace($patterns, '', $text); // 允许表情符号和其他图标 $filteredText = preg_replace('/[\x{1F600}-\x{1F64F}]|\x{1F300}-\x{1F5FF}|\x{1F680}-\x{1F6FF}|\x{2600}-\x{26FF}|\x{2700}-\x{27BF}/u', '$0', $filteredText); // 处理可能出现的连续空格 $filteredText = preg_replace('/\s+/', ' ', $filteredText); // 去除前后的空格 $filteredText = trim($filteredText); // 转换 HTML 实体 $filteredText = htmlentities($filteredText, ENT_QUOTES, 'UTF-8'); return $filteredText; } // 示例调用 $text = '<script>alert("XSS")</script><img src="https://example.com/image.jpg">'; $filteredText = filterRichText($text); echo $filteredText;
2025年03月13日
91 阅读
0 评论
0 点赞
2025-03-13
【PHP】获取二维数组里面最小的值
/** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/12/5 17:16 * @param $array * @return array * @Description:获取一个二维数组,数据最小的,并返回对应的key和value */ public function getMinValueKey($array) { $minValue = PHP_INT_MAX; $desiredKey = null; foreach ($array as $key => $subArray) { foreach ($subArray as $subKey => $value) { if ($value < $minValue) { $minValue = $value; $desiredKey = $subKey; } } } return [$desiredKey, $minValue]; } //使用场景 $inatanceMap = new \app\common\lib\map\baidu\Lnglat($this->param['ac_address']); $lnglat = $inatanceMap->addressToLngLat(); $this->param['u_lng'] = $lnglat['lng'];//经度 $this->param['u_lat'] = $lnglat['lat'];//纬度 $companyList = M("AdminCompany")::getCompanyListUseSelect(); $instanceDis = new \app\common\lib\map\Distance(); foreach ($companyList as $key => $val){ $arrAddress[$key][$val['ac_uuid']] = $instanceDis->getdistance($val['ac_lng'],$val['ac_lat'],$lnglat['lng'],$lnglat['lat']); } $instanceArr = new \app\common\lib\data\Arr(); list($minKey, $minValue) = $instanceArr->getMinValueKey($arrAddress); $this->param['u_company_uuid'] = $minKey; $this->param['u_address'] = $this->param['ac_address'];
2025年03月13日
92 阅读
0 评论
0 点赞
2025-03-13
【PHP】按照个商品金额,等比例分配优惠劵
/** * @Author:小破孩 * @Email:3584685883@qq.com * @Time:2024/11/23 11:41 * @param $products ['id' => 'price','id' => price] * @param $totalCouponAmount 优惠劵优惠金额 * @return array * @Description:按照商品比例拆分优惠劵,分配给对应的商品 */ public function getSplitCoupon($products, $totalCouponAmount) { $totalAmount = array_sum($products); $discounts = []; $allocatedDiscount = 0; foreach ($products as $id => $amount) { $ratio = $amount / $totalAmount; $discount = $ratio * $totalCouponAmount; $roundedDiscount = round($discount, 2); $discounts[$id] = $roundedDiscount; $allocatedDiscount += $roundedDiscount; } // 调整以使总和为指定的优惠券总额 $diff = $totalCouponAmount - $allocatedDiscount; if ($diff!= 0) { $sortedDiscounts = $discounts; arsort($sortedDiscounts); $i = 0; foreach ($sortedDiscounts as $id => $discount) { if ($i < abs($diff)) { $discounts[$id] += ($diff > 0)? 0.01 : -0.01; } $i++; } } return $discounts; }
2025年03月13日
92 阅读
0 评论
0 点赞
2024-10-26
【ThinkPHP】最新版本上传文件的类
<?php namespace app\common\lib\file; use think\Exception; use think\exception\ValidateException; class Uploads { private $domain; protected $name; protected $type; protected $module; protected $image; public function __construct($name = '',$image = []) { $this->name = $name; $this->module = app('http')->getName(); $this->image = $image; $this->domain = Request()->domain(); } protected $config = [ 'image' => [ 'validate' => [ 'size' => 10*1024*1024, 'ext' => 'jpg,png,gif,jpeg', ], 'path' => '/images', ], 'audio' => [ 'validate' => [ 'size' => 100*1024*1024, 'ext' => 'mp3,wav,cd,ogg,wma,asf,rm,real,ape,midi', ], 'path' => '/audios', ], 'video' => [ 'validate' => [ 'size' => 100*1024*1024, 'ext' => 'mp4,avi,rmvb,rm,mpg,mpeg,wmv,mkv,flv', ], 'path' => '/videos', ], 'file' => [ 'validate' => [ 'size' => 5*1024*1024, 'ext' => 'doc,docx,xls,xlsx,pdf,ppt,pptx,txt,rar,zip,pem,p12', ], 'path' => '/files', ], ]; private function determineFileType($file) { $mime = $file->getMime(); if (strpos($mime, 'image/') === 0) { $this->type = 'image'; } elseif (strpos($mime, 'video/') === 0) { $this->type = 'video'; } elseif (strpos($mime, 'audio/') === 0) { $this->type = 'audio'; } else { $this->type = 'file'; } if (!in_array($this->type, array_keys($this->config))) { throw new ValidateException("the file type does not exist"); } validate(['file' => self::validateFile()])->check(['file' => $file]); } public function upfile($infoSwitch = false,$savelocal = 'local'){ try{ $file = request()->file($this->name); //检测文件 if($file == null) throw new ValidateException("the file cannot be empty"); //验证文件 $this->determineFileType($file); //上传文件 switch ($savelocal){ case 'aliyun': $savename = \think\facade\Filesystem::disk('aliyun')->putFile( $this->module.$this->config[$this->type]['path'], $file); break; case 'qiniu': $savename = \think\facade\Filesystem::disk('qiniu')->putFile( $this->module.$this->config[$this->type]['path'], $file); break; case 'qcloud': $savename = \think\facade\Filesystem::disk('qcloud')->putFile( $this->module.$this->config[$this->type]['path'], $file); break; case 'local': $savename = \think\facade\Filesystem::disk('public')->putFile( $this->module.$this->config[$this->type]['path'], $file); break; default : $savename = \think\facade\Filesystem::disk('public')->putFile( $this->module.$this->config[$this->type]['path'], $file); break; } // $savename = \think\facade\Filesystem::disk('public')->putFile( $this->module.$this->config[$this->type]['path'], $file); // $savename = \think\facade\Filesystem::disk('aliyun')->putFile( 'topic', $file); //返回文件详情和文件地址 if($infoSwitch){ return self::getFileInfo($file,$savename); } return $this->domain.config('filesystem.disks.public.url').'/'.str_replace('\\','/',$savename); }catch (\think\exception\ValidateException $e){ return show(100,self::languageChange($e->getMessage())); } } private function validateFile(){ if(empty($this->image)){ $validataType = [ 'fileSize' => $this->config[$this->type]['validate']['size'], 'fileExt' => $this->config[$this->type]['validate']['ext'], ]; }else{ if(is_array($this->image)) throw new ValidateException(""); $validataType = [ 'fileSize' => $this->config[$this->type]['validate']['size'], 'fileExt' => $this->config[$this->type]['validate']['ext'], 'image' => $this->image //示例值 [200,200] ]; } return $validataType; } private function languageChange($msg){ $data = [ 'the file type does not exist' => '文件类型不存在!', 'the file cannot be empty' => '文件不能为空!', 'unknown upload error' => '未知上传错误!', 'file write error' => '文件写入失败!', 'upload temp dir not found' => '找不到临时文件夹!', 'no file to uploaded' => '没有文件被上传!', 'only the portion of file is uploaded' => '文件只有部分被上传!', 'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!', 'upload write error' => '文件上传保存错误!', ]; return $data[$msg] ?? $msg; } private function getFileInfo($file,$savename){ $info = [ 'path' => config('filesystem.disks.public.url').'/'.str_replace('\\','/',$savename), 'url' => $this->domain.config('filesystem.disks.public.url').'/'.str_replace('\\','/',$savename), 'size' => $file->getSize(), 'name' => $file->getOriginalName(), 'mime' => $file->getMime(), 'ext' => $file->extension(), 'type' => $this->type ]; return $info; } public function __clone() { throw new Exception("Cloning operation is not allowed"); // TODO: Implement __clone() method. } // 使用方法 : // $instanceUpload = new Uploads($fileName); // $info = $instanceUpload->upfile(true); } 如果要用建议封装一下,使用interface定义个规范,这里更像一个方法函数
2024年10月26日
161 阅读
0 评论
0 点赞
2024-06-23
【PHP】H5微信网页自定义分享功能实现
<?php namespace app\index\lib\wechat; header("Access-Control-Allow-Origin:*"); class share { public $appid; public $secret; // 步骤1.appid和secret //header("Access-Control-Allow-Origin:*"); //$appid = "appid"; //$secret = "secret"; public function __construct($appid,$secret) { $this->appid = $appid; $this->secret = $secret; } // 步骤2.生成签名的随机串 public function nonceStr($length){ $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJK1NGJBQRSTUVWXYZ';//随即串,62个字符 $strlen = 62; while($length > $strlen){ $str .= $str; $strlen += 62; } $str = str_shuffle($str); return substr($str,0,$length); } // 步骤3.获取access_token public function http_get($url){ $oCurl = curl_init(); if(stripos($url,"https://")!==FALSE){ curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 } curl_setopt($oCurl, CURLOPT_URL, $url); curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 ); $sContent = curl_exec($oCurl); $aStatus = curl_getinfo($oCurl); curl_close($oCurl); if(intval($aStatus["http_code"])==200){ return $sContent; }else{ return false; } } // 步骤4.获取ticket public function getTicket(){ $result = $this->http_get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->appid.'&secret='.$this->secret); $json = json_decode($result,true); $access_token = $json['access_token']; $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$access_token"; $res = json_decode ( $this->http_get ( $url ) ); return $res->ticket; } // 步骤5.生成wx.config需要的参数 //$surl = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; //$ws = getWxConfig( $ticket,$surl,time(),nonceStr(16) ); // public function getWxConfig($jsapiTicket,$url,$timestamp,$nonceStr) { public function getWxConfig() { $jsapiTicket=$this->getTicket(); $url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; $timestamp = time(); $nonceStr = $this->nonceStr(rand(8,15)); $string = "jsapi_ticket=".$jsapiTicket."&noncestr=".$nonceStr."×tamp=".$timestamp."&url=".$url; $signature = sha1 ($string); $WxConfig["appId"] = $this->appid; $WxConfig["nonceStr"] = $nonceStr; $WxConfig["timestamp"] = $timestamp; $WxConfig["url"] = $url; $WxConfig["signature"] = $signature; $WxConfig["rawString"] = $string; return $WxConfig; } } public function getWxShareConfig(){ $instanceWxShare = new \app\index\lib\wechat\share('appid','secret'); return $instanceWxShare->getWxConfig(); } <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <script> // console.log(timestamp); wx.config({ debug: false, appId: '{$wxsc.appId}', timestamp: '{$wxsc.timestamp}', nonceStr: '{$wxsc.nonceStr}', signature: '{$wxsc.signature}', jsApiList: ['updateAppMessageShareData','updateTimelineShareData'] }); wx.ready(function () { //需在用户可能点击分享按钮前就先调用 wx.updateAppMessageShareData({ title: '医博:', // 分享标题 desc: '专业肛肠、胃肠、中医交流平台,为业界名专家们搭建教学、学术平台,为专业医生提供手术直播、科普交流基地,为学者提供学习、沟通、上升平台。', // 分享描述 link: 'https://wx.kmyebo.com', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl: 'https://wx.kmyebo.com/yb_share_icon.jpg', // 分享图标 success: function () { // 设置成功 } }) }); wx.ready(function () { //需在用户可能点击分享按钮前就先调用 wx.updateTimelineShareData({ title: '医博:', // 分享标题 link: 'https://wx.kmyebo.com', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl: 'https://wx.kmyebo.com', // 分享图标 success: function () { // 设置成功 } }) }); </script>http://www.xmyfw.com.cn/pc/show.php?id=55
2024年06月23日
204 阅读
0 评论
0 点赞
2023-07-10
【PHP】基于thinkPHP使用easywechat发送统一下发消息
好的,您可以按照以下步骤使用thinkPHP和easywechat发送下发统一消息:首先,确保您已经安装了thinkPHP和easywechat。您可以使用Composer来安装它们:composer require topthink/thinkcomposer require overtrue/wechat在thinkPHP项目中创建一个控制器(例如MessageController),并在其中添加一个方法(例如sendUnifiedMessage)来处理发送下发统一消息的逻辑。<?php namespace app\controller; use think\Controller; use EasyWeChat\Factory; class MessageController extends Controller { public function sendUnifiedMessage() { // 创建 EasyWeChat 实例 $config = [ 'app_id' => 'your_app_id', 'secret' => 'your_app_secret', // 其他配置项... ]; $app = Factory::officialAccount($config); // 发送下发统一消息 $result = $app->broadcasting->send([ 'touser' => 'openid1,openid2', // 接收消息的用户openid列表 'msgtype' => 'text', 'text' => [ 'content' => '这是一条测试消息' ] ]); // 处理发送结果 if ($result['errcode'] === 0) { return '消息发送成功'; } else { return '消息发送失败:' . $result['errmsg']; } } } 请注意,上述代码中的your_app_id和your_app_secret应替换为您自己的微信公众号的AppID和AppSecret。在路由中定义一个访问该方法的路由。您可以在route/route.php文件中添加以下代码:<?php use think\facade\Route; Route::get('message/send', 'MessageController/sendUnifiedMessage'); 现在,您可以通过访问/message/send来触发发送下发统一消息的逻辑。请注意,上述代码仅为示例,您可能需要根据您的实际需求进行修改和调整。另外,确保您已正确配置微信公众号的相关信息,并且您的服务器能够正常访问到微信服务器。
2023年07月10日
141 阅读
0 评论
0 点赞
2022-12-26
【ThinkPHP】ThinkPHP6处理接口版本问题
'domain_bind' => [ 'api' => 'api', // blog子域名绑定到blog应用 'admin.tp.com' => 'admin', // 完整域名绑定 '*' => 'home', // 二级泛域名绑定到home应用 ], // url版本路由,在url地址上带版本号 Route::rule(':version/:controller/:function', ':version.:controller/:function') ->allowCrossDomain([ 'Access-Control-Allow-Origin' => '*', // //解决跨域问题 'Access-Control-Allow-Methods' => '*', 'Access-Control-Allow-Headers' => '*', 'Access-Control-Request-Headers' => '*' ]); // 头部模式(请求头部带版本号) $version = request()->header('version'); //默认跳转到v1版本 if ($version == null) $version = "v1"; Route::rule(':controller/:function', $version . '.:controller/:function');
2022年12月26日
303 阅读
0 评论
0 点赞
2022-11-03
【ThinkPHP】tp6获取应用名
protected $filter = ['htmlspecialchars']; public function app_name() { return App('http')->getName(); }
2022年11月03日
326 阅读
0 评论
0 点赞
2022-08-16
【PHP】PHPEmail的使用
第一步:使用composer安装phpmailercomposer require phpmailer/phpmailer第二步:common.php写个发送邮件的函数(腾讯邮箱的为例)/** * 系统邮件发送函数 * @param string $tomail 接收邮件者邮箱 * @param string $name 接收邮件者名称 * @param string $subject 邮件主题 * @param string $body 邮件内容 * @param string $attachment 附件列表 * @return boolean * @author static7 <static7@qq.com> */ function send_mail($tomail, $name, $subject = '', $body = '', $attachment = null) { $mail = new \PHPMailer(); //实例化PHPMailer对象 $mail->CharSet = 'UTF-8'; //设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码 $mail->IsSMTP(); // 设定使用SMTP服务 $mail->SMTPDebug = 0; // SMTP调试功能 0=关闭 1 = 错误和消息 2 = 消息 $mail->SMTPAuth = true; // 启用 SMTP 验证功能 $mail->SMTPSecure = 'ssl'; // 使用安全协议 $mail->Host = "smtp.exmail.qq.com"; // SMTP 服务器 $mail->Port = 465; // SMTP服务器的端口号 $mail->Username = "static7@qq.com"; // SMTP服务器用户名 $mail->Password = ""; // SMTP服务器密码 $mail->SetFrom('static7@qq.com', 'static7'); $replyEmail = ''; //留空则为发件人EMAIL $replyName = ''; //回复名称(留空则为发件人名称) $mail->AddReplyTo($replyEmail, $replyName); $mail->Subject = $subject; $mail->MsgHTML($body); $mail->AddAddress($tomail, $name); if (is_array($attachment)) { // 添加附件 foreach ($attachment as $file) { is_file($file) && $mail->AddAttachment($file); } } return $mail->Send() ? true : $mail->ErrorInfo; }第三步:控制器方法里写发送的内容/** * tp5邮件 * @param * @author staitc7 <static7@qq.com> * @return mixed */ public function email() { $toemail='static7@qq.com'; $name='static7'; $subject='QQ邮件发送测试'; $content='恭喜你,邮件测试成功。'; dump(send_mail($toemail,$name,$subject,$content)); }第4步:测试发送请自行测试转发:https://www.thinkphp.cn/topic/44477.html
2022年08月16日
345 阅读
0 评论
0 点赞
2022-06-27
【PHP】TP6.0验证码接口
安装验证码扩展:composer require topthink/think-captcha创建验证码接口: public function setYzm(){ $captcha_img = Captcha_src(); $src = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['SERVER_NAME'].'/api'.captcha_src(); ob_clean(); //清除缓冲区,防止出现“图像因其本身有错无法显示'的问题 $type = getimagesize($src)['mime']; //获取图片类型 header("Content-Type:{$type}"); $imgData = file_get_contents($src); //获取图片二进制流 $base64String = 'data:' . $type . ';base64,' . base64_encode($imgData); return show(200,'请求成功',$base64String); } 可以不用base64处理直接返回验证码地址 public function checkYzm($yzm){ if(!Captcha::checkApi($yzm)) throw new Exception('验证码验证失败~'); return true; }修改底层配置路径:vendor/topthink/think-captcha/src/Captcha.php/** * 创建验证码 * @return array * @throws Exception */ protected function generate(): array { $bag = ''; if ($this->math) { $this->useZh = false; $this->length = 5; $x = random_int(10, 30); $y = random_int(1, 9); $bag = "{$x} + {$y} = "; $key = $x + $y; $key .= ''; } else { if ($this->useZh) { $characters = preg_split('/(?<!^)(?!$)/u', $this->zhSet); } else { $characters = str_split($this->codeSet); } for ($i = 0; $i < $this->length; $i++) { $bag .= $characters[rand(0, count($characters) - 1)]; } $key = mb_strtolower($bag, 'UTF-8'); } $hash = password_hash($key, PASSWORD_BCRYPT, ['cost' => 10]); $this->session->set('captcha', [ 'key' => $hash, ]); //加上这行代码,便于后续校验验证码 if(empty(cache($key))){ cache($key, $hash, 5*60); }else{ return $this->generate(); } //加上这行代码,便于后续校验验证码 return [ 'value' => $bag, 'key' => $hash, ]; } /** * 验证验证码是否正确 * @access public * @param string $code 用户验证码 * @return bool 用户验证码是否正确 */ public function checkApi(string $code): bool { if (!cache($code)) { return false; } $key = cache($code); $code = mb_strtolower($code, 'UTF-8'); $res = password_verify($code, $key); if ($res) { cache($code,NULL); } return $res; }
2022年06月27日
359 阅读
0 评论
0 点赞
2022-06-23
【PHP】ThinkPHP6 公共 上传到本地的方法 附带使用方法
<?php namespace app\common\lib\files; use think\Exception; use think\exception\ValidateException; class upload { private $domain; protected $name; protected $type; protected $module; protected $image; public function __construct($name = '',$type = 'image',$image = []) { $this->name = $name; $this->type = $this->checkUpload($type); $this->module = request()->app_name(); $this->image = $image; $this->domain = Request()->domain(); } protected $config = [ 'image' => [ 'validate' => [ 'size' => 10*1024*1024, 'ext' => 'jpg,png,gif,jpeg', ], 'path' => '/images', ], 'audio' => [ 'validate' => [ 'size' => 100*1024*1024, 'ext' => 'mp3,wav,cd,ogg,wma,asf,rm,real,ape,midi', ], 'path' => '/audios', ], 'video' => [ 'validate' => [ 'size' => 100*1024*1024, 'ext' => 'mp4,avi,rmvb,rm,mpg,mpeg,wmv,mkv,flv', ], 'path' => '/videos', ], 'file' => [ 'validate' => [ 'size' => 5*1024*1024, 'ext' => 'doc,docx,xls,xlsx,pdf,ppt,txt,rar,zip,pem,p12', ], 'path' => '/files', ], ]; private function checkUpload($type){ try{ if(empty($_FILES) || empty($_FILES[$this->name])) throw new Exception("未上传文件!"); if(!in_array($type,array_keys($this->config))) throw new Exception("文件类型不存在!"); return $type; }catch (Exception $e){ return \app\common\controller\Base::show(100,$e->getMessage()); } } public function upfile($infoSwitch = false){ $file = request()->file($this->name); try{ if($file == null) throw new ValidateException("the file cannot be empty"); validate(['file' => self::validateFile()])->check(['file' => $file]); $savename = \think\facade\Filesystem::disk('public')->putFile( $this->module.$this->config[$this->type]['path'], $file); if($infoSwitch){ return self::getFileInfo($file,$savename); } return $savename; }catch (\think\exception\ValidateException $e){ return \app\common\controller\Base::show(100,self::languageChange($e->getMessage())); } } private function validateFile(){ if(empty($this->image)){ $validataType = [ 'fileSize' => $this->config[$this->type]['validate']['size'], 'fileExt' => $this->config[$this->type]['validate']['ext'], ]; }else{ if(is_array($this->image)) throw new ValidateException(""); $validataType = [ 'fileSize' => $this->config[$this->type]['validate']['size'], 'fileExt' => $this->config[$this->type]['validate']['ext'], 'image' => $this->image //示例值 [200,200] ]; } return $validataType; } private function languageChange($msg){ $data = [ 'the file cannot be empty' => '文件不能为空!', 'unknown upload error' => '未知上传错误!', 'file write error' => '文件写入失败!', 'upload temp dir not found' => '找不到临时文件夹!', 'no file to uploaded' => '没有文件被上传!', 'only the portion of file is uploaded' => '文件只有部分被上传!', 'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!', 'upload write error' => '文件上传保存错误!', ]; return $data[$msg] ?? $msg; } private function getFileInfo($file,$savename){ $info = [ 'path' => config('filesystem.disks.public.url').'/'.str_replace('\\','/',$savename), 'url' => $this->domain.config('filesystem.disks.public.url').'/'.str_replace('\\','/',$savename), 'size' => $file->getSize(), 'name' => $file->getOriginalName(), 'mime' => $file->getMime(), 'ext' => $file->extension() ]; return $info; } } > 使用方法 : > > $instanceUpload = new upload($fileName,$fileType); > $info = $instanceUpload->upfile(true);
2022年06月23日
247 阅读
0 评论
0 点赞
1
2