fix: Add .php-cs-fixer.php and update many files

Add PHP CS Fixer configuration (.php-cs-fixer.php) to enforce coding style and apply corresponding updates across the codebase. Numerous plugins (think-library and many think-plugs-*) and core config files (cache, database, phinx, worker) were updated along with controllers, services, models, storage adapters, helpers and tests to conform to style fixes and minor compatibility/refactors.
This commit is contained in:
邹景立 2026-02-01 02:01:37 +08:00
parent 6b3e985747
commit 987ad41765
453 changed files with 22143 additions and 20383 deletions

120
.php-cs-fixer.php Normal file
View File

@ -0,0 +1,120 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
use PhpCsFixer\Runner\Parallel\ParallelConfig;
$header = <<<'EOF'
+----------------------------------------------------------------------
| Payment Plugin for ThinkAdmin
+----------------------------------------------------------------------
| 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
+----------------------------------------------------------------------
| 官方网站: https://thinkadmin.top
+----------------------------------------------------------------------
| 开源协议 ( https://mit-license.org )
| 免责声明 ( https://thinkadmin.top/disclaimer )
| 会员特权 ( https://thinkadmin.top/vip-introduce )
+----------------------------------------------------------------------
| gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
| github 代码仓库https://github.com/zoujingli/ThinkAdmin
+----------------------------------------------------------------------
EOF;
$config = new Config();
$config->setRiskyAllowed(true)->setParallelConfig(new ParallelConfig(8, 24));
$finder = Finder::create()->in(__DIR__)->exclude(['vendor', 'public', 'runtime']);
return $config->setFinder($finder)->setUsingCache(false)->setRules([
'@PSR2' => true,
'@Symfony' => true,
'@DoctrineAnnotation' => true,
'@PhpCsFixer' => true,
'header_comment' => [
'comment_type' => 'PHPDoc',
'header' => $header,
'separate' => 'none',
'location' => 'after_declare_strict',
],
'array_syntax' => [
'syntax' => 'short',
],
'list_syntax' => [
'syntax' => 'short',
],
'blank_line_before_statement' => [
'statements' => [
'declare',
],
],
'general_phpdoc_annotation_remove' => [
'annotations' => [
'author',
],
],
'ordered_imports' => [
'imports_order' => [
'class', 'function', 'const',
],
'sort_algorithm' => 'alpha',
],
'single_line_comment_style' => [
'comment_types' => [
],
],
'yoda_style' => [
'always_move_variable' => false,
'equal' => false,
'identical' => false,
],
'phpdoc_align' => [
'align' => 'left',
],
'multiline_whitespace_before_semicolons' => [
'strategy' => 'no_multi_line',
],
'constant_case' => [
'case' => 'lower',
],
'encoding' => true, // PHP代码必须只使用没有BOM的UTF-8
'line_ending' => true, // 所有的PHP文件编码必须一致
'single_quote' => true, // 简单字符串应该使用单引号代替双引号
'no_empty_statement' => true, // 不应该存在空的结构体
'standardize_not_equals' => true, // 使用 <> 代替 !=
'blank_line_after_namespace' => true, // 命名空间之后空一行
'no_empty_phpdoc' => true, // 不应该存在空的 phpdoc
'no_empty_comment' => true, // 不应该存在空注释
'no_singleline_whitespace_before_semicolons' => true, // 禁止在关闭分号前使用单行空格
'concat_space' => ['spacing' => 'one'], // 连接字符是否需要空格,可选配置项 none:不需要 one:一个空格
'no_leading_import_slash' => true, // use 语句中取消前置斜杠
'cast_spaces' => ['space' => 'none'],
'class_attributes_separation' => true,
'combine_consecutive_unsets' => true,
'declare_strict_types' => true,
'lowercase_static_reference' => true,
'linebreak_after_opening_tag' => true,
'multiline_comment_opening_closing' => true,
'no_useless_else' => true,
'no_unused_imports' => true,
'not_operator_with_successor_space' => false,
'not_operator_with_space' => false,
'ordered_class_elements' => true,
'php_unit_strict' => false,
'phpdoc_separation' => false,
]);

View File

@ -1,18 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Static Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-static
// | github 代码仓库https://github.com/zoujingli/think-plugs-static
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace app\index\controller;

View File

@ -36,9 +36,13 @@
"zoujingli/think-plugs-wuma": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
"zoujingli/think-plugs-helper": "*"
},
"scripts": {
"sync": [
"php-cs-fixer fix"
],
"test": [
"php -m"
]
@ -100,4 +104,4 @@
"zoujingli/think-install": true
}
}
}
}

View File

@ -1,59 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | Static Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-static
// | github 代码仓库https://github.com/zoujingli/think-plugs-static
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
return [
// 默认缓存驱动
'default' => env('CACHE_TYPE', 'file'),
// 缓存连接配置
'stores' => [
'file' => [
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
'type' => 'File',
// 缓存保存目录
'path' => '',
'path' => '',
// 缓存名称前缀
'prefix' => '',
'prefix' => '',
// 缓存有效期 0 表示永久缓存
'expire' => 0,
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制
'serialize' => [],
'serialize' => [],
],
'safe' => [
'safe' => [
// 驱动方式
'type' => 'File',
'type' => 'File',
// 缓存保存目录
'path' => syspath('safefile/cache/'),
'path' => syspath('safefile/cache/'),
// 缓存名称前缀
'prefix' => '',
'prefix' => '',
// 缓存有效期 0 表示永久缓存
'expire' => 0,
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制
'serialize' => [],
'serialize' => [],
],
'redis' => [
// 驱动方式
'type' => 'redis',
'host' => env('CACHE_REDIS_HOST', '127.0.0.1'),
'port' => env('CACHE_REDIS_PORT', 6379),
'select' => env('CACHE_REDIS_SELECT', 0),
'type' => 'redis',
'host' => env('CACHE_REDIS_HOST', '127.0.0.1'),
'port' => env('CACHE_REDIS_PORT', 6379),
'select' => env('CACHE_REDIS_SELECT', 0),
'password' => env('CACHE_REDIS_PASSWORD', ''),
]
],
],
];
];

View File

@ -1,83 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | Static Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-static
// | github 代码仓库https://github.com/zoujingli/think-plugs-static
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
return [
// 默认使用的数据库连接配置
'default' => env('DB_TYPE', 'sqlite'),
'default' => env('DB_TYPE', 'sqlite'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
'auto_timestamp' => true,
'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 数据库连接配置信息
'connections' => [
'mysql' => [
'connections' => [
'mysql' => [
// 数据库类型
'type' => 'mysql',
'type' => 'mysql',
// 服务器地址
'hostname' => env('DB_MYSQL_HOST', '127.0.0.1'),
'hostname' => env('DB_MYSQL_HOST', '127.0.0.1'),
// 服务器端口
'hostport' => env('DB_MYSQL_PORT', '3306'),
'hostport' => env('DB_MYSQL_PORT', '3306'),
// 数据库名
'database' => env('DB_MYSQL_DATABASE', 'thinkadmin'),
'database' => env('DB_MYSQL_DATABASE', 'thinkadmin'),
// 用户名
'username' => env('DB_MYSQL_USERNAME', 'root'),
'username' => env('DB_MYSQL_USERNAME', 'root'),
// 密码
'password' => env('DB_MYSQL_PASSWORD', ''),
'password' => env('DB_MYSQL_PASSWORD', ''),
// 数据库连接参数
'params' => [],
'params' => [],
// 数据库表前缀
'prefix' => env('DB_MYSQL_PREFIX', ''),
'prefix' => env('DB_MYSQL_PREFIX', ''),
// 数据库编码默认采用 utf8mb4
'charset' => env('DB_MYSQL_CHARSET', 'utf8mb4'),
'charset' => env('DB_MYSQL_CHARSET', 'utf8mb4'),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
'slave_no' => '',
// 检查字段是否存在
'fields_strict' => true,
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL执行日志
'trigger_sql' => true,
'trigger_sql' => true,
// 开启字段类型缓存
'fields_cache' => isOnline(),
'fields_cache' => isOnline(),
],
'sqlite' => [
// 数据库类型
'type' => 'sqlite',
'type' => 'sqlite',
// 数据库文件
'database' => syspath('database/sqlite.db'),
'database' => syspath('database/sqlite.db'),
// 数据库编码默认采用 utf8
'charset' => 'utf8',
'charset' => 'utf8',
// 监听执行日志
'trigger_sql' => true,
// 其他参数字段
'deploy' => 0,
'suffix' => '',
'prefix' => '',
'hostname' => '',
'hostport' => '',
'username' => '',
'password' => '',
'deploy' => 0,
'suffix' => '',
'prefix' => '',
'hostname' => '',
'hostport' => '',
'username' => '',
'password' => '',
],
],
];

View File

@ -1,19 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Static Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-static
// | github 代码仓库https://github.com/zoujingli/think-plugs-static
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
return [
// 忽略数据表,填写表名
'ignore' => [],
@ -21,4 +24,4 @@ return [
'tables' => [],
// 备份数据表,填写表名
'backup' => [],
];
];

View File

@ -1,52 +1,52 @@
<?php
// +----------------------------------------------------------------------
// | Worker Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 开源协议 ( http://www.apache.org/licenses/LICENSE-2.0 )
// | 配置参考 ( https://www.workerman.net/doc/workerman/worker/properties.html )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-worker
// | github 代码仓库https://github.com/zoujingli/think-plugs-worker
// +----------------------------------------------------------------------
// | 配置参数参数https://www.workerman.net/doc/workerman/worker/properties.html
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
return [
// 服务监听地址
'host' => '127.0.0.1',
'host' => '127.0.0.1',
// 服务监听端口
'port' => 2346,
'port' => 2346,
// 套接字上下文选项
'context' => [],
'context' => [],
// 高级自定义服务类
'classes' => '',
'classes' => '',
// 消息请求回调处理
'callable' => null,
// 服务进程参数配置
'worker' => [
'name' => 'ThinkAdmin',
'worker' => [
'name' => 'ThinkAdmin',
'count' => 4,
],
// 监控文件变更重载,仅 Debug 模式有效
'files' => [
'files' => [
// 监控检测间隔(单位秒,零不监控)
'time' => 3,
// 文件监控目录(默认监控 app+config 目录)
'path' => [],
// 文件监控后缀(默认监控 所有 文件)
'exts' => ['*']
'exts' => ['*'],
],
// 监控内存超限重载,仅 Debug 模式有效
'memory' => [
'memory' => [
// 监控检测间隔(单位秒,零不监控)
'time' => 60,
'time' => 60,
// 限制内存大小(可选单位有 G M K
'limit' => '1G'
'limit' => '1G',
],
];
];

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -22,28 +24,27 @@ use think\exception\HttpResponseException;
/**
* 表单模板构建器
* 后面会在兼容的基础上慢慢完善
* 后面会在兼容的基础上慢慢完善.
* @class Builder
* @deprecated 试验中建议不使用
* @package think\admin
*/
class Builder
{
/**
* 生成类型
* 生成类型.
* @var string
*/
private $type;
/**
* 显示方式
* 显示方式.
* @var string
*/
private $mode;
/**
* 当前控制器
* @var \think\admin\Controller
* 当前控制器.
* @var Controller
*/
private $class;
@ -54,23 +55,23 @@ class Builder
private $action;
/**
* 表单变量
* 表单变量.
* @var string
*/
private $variable = '$vo';
/**
* 表单项目
* 表单项目.
* @var array
*/
private $fields = [];
private $buttons = [];
/**
* Constructer
* Constructer.
* @param string $type 页面类型
* @param string $mode 页面模式
* @param \think\admin\Controller $class
*/
public function __construct(string $type, string $mode, Controller $class)
{
@ -80,10 +81,9 @@ class Builder
}
/**
* 创建表单生成器
* 创建表单生成器.
* @param string $type 页面类型
* @param string $mode 页面模式
* @return \think\admin\Builder
*/
public static function mk(string $type = 'form', string $mode = 'modal'): Builder
{
@ -92,7 +92,6 @@ class Builder
/**
* 设置表单地址
* @param string $url
* @return $this
*/
public function setAction(string $url): Builder
@ -102,8 +101,7 @@ class Builder
}
/**
* 设置变量名称
* @param string $name
* 设置变量名称.
* @return $this
*/
public function setVariable(string $name): Builder
@ -113,7 +111,218 @@ class Builder
}
/**
* 增加输入表单元素
* 创建文本输入框架.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param array $attrs 附加属性
* @param mixed $remark
* @return $this
*/
public function addTextArea(string $name, string $title, string $substr = '', bool $required = false, $remark = '', array $attrs = []): Builder
{
if ($required) {
$attrs['required'] = 'required';
}
$html = "\n\t\t" . '<label class="layui-form-item block relative">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : 'label-required-prev', $title, $substr);
$html .= "\n\t\t\t" . sprintf('<textarea name="%s" %s placeholder="请输入%s" class="layui-textarea">{%s.%s|default=\'\'}</textarea>', $name, $this->_attrs($attrs), $title, $this->variable, $name);
if ($remark) {
$html .= "\n\t\t\t" . sprintf('<span class="help-block">%s</span>', $remark);
}
$this->fields[] = "{$html}\n\t\t</lable>";
return $this;
}
/**
* 创建 Text 输入.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $remark 字段备注
* @param bool $required 是否必填
* @param ?string $pattern 验证规则
* @param array $attrs 附加属性
* @return $this
*/
public function addTextInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
{
$attrs['vali-name'] = $title;
if ($required) {
$attrs['required'] = 'required';
}
if (is_string($pattern)) {
$attrs['pattern'] = $pattern;
}
return $this->addInput($name, $title, $substr, $remark, $attrs);
}
/**
* 创建密钥输入框.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $remark 字段备注
* @param bool $required 是否必填
* @param ?string $pattern 验证规则
* @param array $attrs 附加属性
* @return $this
*/
public function addPassInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
{
$attrs['type'] = 'password';
return $this->addTextInput($name, $title, $substr, $required, $remark, $pattern, $attrs);
}
/**
* 添加取消按钮.
* @param string $name 按钮名称
* @param string $confirm 确认提示
* @return $this
*/
public function addCancelButton(string $name = '取消编辑', string $confirm = '确定要取消编辑吗?'): Builder
{
return $this->addButton($name, $confirm, 'button', 'layui-btn-danger', ['data-close' => null]);
}
/**
* 添加提交按钮.
* @param string $name 按钮名称
* @param string $confirm 确认提示
* @return $this
*/
public function addSubmitButton(string $name = '保存数据', string $confirm = ''): Builder
{
return $this->addButton($name, $confirm, 'submit');
}
/**
* 添加上传单图字段.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadOneImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) {
$attrs['required'] = 'required';
}
return $this->_addUploadOneView($name, $title, $substr, $attrs);
}
/**
* 添加上传视频字段.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadOneVideo(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) {
$attrs['required'] = 'required';
}
return $this->_addUploadOneView($name, $title, $substr, $attrs, 'video');
}
/**
* 创建上传多图字段.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadMulImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) {
$attrs['required'] = 'required';
}
$attrs = array_merge($attrs, ['type' => 'hidden', 'placeholder' => "请上传{$title} ( 多图 )"]);
$html = "\n\t\t" . '<div class="layui-form-item">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : 'label-required-prev ', $title, $substr);
$html .= "\n\t\t\t" . '<div class="layui-textarea help-images layui-bg-gray">';
$html .= "\n\t\t\t\t" . sprintf('<input name="%s" %s value="{%s.%s|default=\'\'}">', $name, $this->_attrs($attrs), $this->variable, $name);
$html .= "\n\t\t\t" . '</div>' . "\n\t\t" . '</div>';
$html .= "\n\t\t" . sprintf('<script>$("input[name=%s]").uploadMultipleImage()</script>', $name);
$this->fields[] = $html;
return $this;
}
/**
* 创建复选框字段.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $vname 变量名称
* @param bool $required 是否必选
* @param array $attrs 附加属性
* @return $this
*/
public function addCheckInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = [], string $type = 'checkbox'): Builder
{
if ($required) {
$attrs['required'] = 'required';
}
$attrs = array_merge($attrs, ['type' => $type, 'lay-ignore' => null, 'name' => $name . ($type === 'checkbox' ? '[]' : '')]);
$html = "\n\t\t" . '<div class="layui-form-item">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : ' label-required-prev', $title, $substr);
$html .= "\n\t\t\t" . '<div class="layui-textarea help-checks layui-bg-gray">';
$html .= "\n\t\t\t\t" . sprintf('<!--{foreach $%s as $k=>$v}item-->', $vname);
$html .= "\n\t\t\t\t" . sprintf('<label class="think-%s label-required-null">', $type);
$html .= "\n\t\t\t\t\t" . sprintf('<!--if{if isset(%s.types) and is_array(%s.types) and in_array($k,%s.types)}-->', $this->variable, $this->variable, $this->variable);
$html .= "\n\t\t\t\t\t" . sprintf('<input value="{$k|default=\'\'}" %s checked> {$v|default=\'\'}', $this->_attrs($attrs));
$html .= "\n\t\t\t\t\t" . '<!--{else}else-->';
$html .= "\n\t\t\t\t\t" . sprintf('<input value="{$k|default=\'\'}" %s> {$v|default=\'\'}', $this->_attrs($attrs)) . "\n";
$html .= "\n\t\t\t\t\t" . '<!--{/if}if-->';
$html .= "\n\t\t\t\t" . '</label>';
$html .= "\n\t\t\t\t" . '<!--{/foreach}end-->';
$this->fields[] = $html . "\n\t\t\t</div>\n\t\t</div>";
return $this;
}
/**
* 添加单选框架字段.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $vname 变量名称
* @param bool $required 是否必选
* @param array $attrs 附加属性
* @return $this
*/
public function addRadioInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = []): Builder
{
return $this->addCheckInput($name, $title, $substr, $vname, $required, $attrs, 'radio');
}
/**
* 显示模板内容.
* @return mixed
*/
public function fetch(array $vars = [])
{
$html = '';
$type = "{$this->type}.{$this->mode}";
if ($type === 'form.page') {
$html = $this->_buildFormPage();
} elseif ($type === 'form.modal') {
$html = $this->_buildFormModal();
}
foreach ($this->class as $k => $v) {
$vars[$k] = $v;
}
throw new HttpResponseException(display($html, $vars));
}
/**
* 增加输入表单元素.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $subtitle 字段子标题
@ -126,80 +335,26 @@ class Builder
$html = "\n\t\t" . '<label class="layui-form-item block relative">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : 'label-required-prev', $title, $subtitle);
$html .= "\n\t\t\t" . sprintf('<input name="%s" %s placeholder="请输入%s" value="{%s.%s|default=\'\'}" class="layui-input">', $name, $this->_attrs($attrs), $title, $this->variable, $name);
if ($remark) $html .= "\n\t\t\t" . sprintf('<span class="help-block">%s</span>', $remark);
if ($remark) {
$html .= "\n\t\t\t" . sprintf('<span class="help-block">%s</span>', $remark);
}
$this->fields[] = "{$html}\n\t\t</label>";
return $this;
}
/**
* 创建文本输入框架
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param array $attrs 附加属性
* @return $this
*/
public function addTextArea(string $name, string $title, string $substr = '', bool $required = false, $remark = '', array $attrs = []): Builder
{
if ($required) $attrs['required'] = 'required';
$html = "\n\t\t" . '<label class="layui-form-item block relative">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : 'label-required-prev', $title, $substr);
$html .= "\n\t\t\t" . sprintf('<textarea name="%s" %s placeholder="请输入%s" class="layui-textarea">{%s.%s|default=\'\'}</textarea>', $name, $this->_attrs($attrs), $title, $this->variable, $name);
if ($remark) $html .= "\n\t\t\t" . sprintf('<span class="help-block">%s</span>', $remark);
$this->fields[] = "{$html}\n\t\t</lable>";
return $this;
}
/**
* 字段属性转换
* @param array $attrs
* @param string $html
* @return string
* 字段属性转换.
*/
protected function _attrs(array $attrs, string $html = ''): string
{
foreach ($attrs as $k => $v) $html .= is_null($v) ? sprintf(' %s', $k) : sprintf(' %s="%s"', $k, $v);
foreach ($attrs as $k => $v) {
$html .= is_null($v) ? sprintf(' %s', $k) : sprintf(' %s="%s"', $k, $v);
}
return $html;
}
/**
* 创建 Text 输入
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $remark 字段备注
* @param boolean $required 是否必填
* @param ?string $pattern 验证规则
* @param array $attrs 附加属性
* @return $this
*/
public function addTextInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
{
$attrs['vali-name'] = $title;
if ($required) $attrs['required'] = 'required';
if (is_string($pattern)) $attrs['pattern'] = $pattern;
return $this->addInput($name, $title, $substr, $remark, $attrs);
}
/**
* 创建密钥输入框
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $remark 字段备注
* @param boolean $required 是否必填
* @param ?string $pattern 验证规则
* @param array $attrs 附加属性
* @return $this
*/
public function addPassInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
{
$attrs['type'] = 'password';
return $this->addTextInput($name, $title, $substr, $required, $remark, $pattern, $attrs);
}
/**
* 添加表单按钮
* 添加表单按钮.
* @param string $name 按钮名称
* @param string $confirm 确认提示
* @param string $type 按钮类型
@ -210,35 +365,15 @@ class Builder
protected function addButton(string $name, string $confirm, string $type, string $class = '', array $attrs = []): Builder
{
$attrs['type'] = $type;
if ($confirm) $attrs['data-confirm'] = $confirm;
if ($confirm) {
$attrs['data-confirm'] = $confirm;
}
$this->buttons[] = sprintf('<button class="layui-btn %s" %s>%s</button>', $class, $this->_attrs($attrs), $name);
return $this;
}
/**
* 添加取消按钮
* @param string $name 按钮名称
* @param string $confirm 确认提示
* @return $this
*/
public function addCancelButton(string $name = '取消编辑', string $confirm = '确定要取消编辑吗?'): Builder
{
return $this->addButton($name, $confirm, 'button', 'layui-btn-danger', ['data-close' => null]);
}
/**
* 添加提交按钮
* @param string $name 按钮名称
* @param string $confirm 确认提示
* @return $this
*/
public function addSubmitButton(string $name = '保存数据', string $confirm = ''): Builder
{
return $this->addButton($name, $confirm, 'submit');
}
/**
* 添加上传单个文件
* 添加上传单个文件.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
@ -268,124 +403,8 @@ class Builder
return $this;
}
/**
* 添加上传单图字段
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadOneImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) $attrs['required'] = 'required';
return $this->_addUploadOneView($name, $title, $substr, $attrs);
}
/**
* 添加上传视频字段
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadOneVideo(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) $attrs['required'] = 'required';
return $this->_addUploadOneView($name, $title, $substr, $attrs, 'video');
}
/**
* 创建上传多图字段
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param bool $required 必填字段
* @param array $attrs 附加属性
* @return $this
*/
public function addUploadMulImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
{
if ($required) $attrs['required'] = 'required';
$attrs = array_merge($attrs, ['type' => 'hidden', 'placeholder' => "请上传{$title} ( 多图 )"]);
$html = "\n\t\t" . '<div class="layui-form-item">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : 'label-required-prev ', $title, $substr);
$html .= "\n\t\t\t" . '<div class="layui-textarea help-images layui-bg-gray">';
$html .= "\n\t\t\t\t" . sprintf('<input name="%s" %s value="{%s.%s|default=\'\'}">', $name, $this->_attrs($attrs), $this->variable, $name);
$html .= "\n\t\t\t" . '</div>' . "\n\t\t" . '</div>';
$html .= "\n\t\t" . sprintf('<script>$("input[name=%s]").uploadMultipleImage()</script>', $name);
$this->fields[] = $html;
return $this;
}
/**
* 创建复选框字段
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $vname 变量名称
* @param bool $required 是否必选
* @param array $attrs 附加属性
* @return $this
*/
public function addCheckInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = [], string $type = 'checkbox'): Builder
{
if ($required) $attrs['required'] = 'required';
$attrs = array_merge($attrs, ['type' => $type, 'lay-ignore' => null, 'name' => $name . ($type === 'checkbox' ? '[]' : '')]);
$html = "\n\t\t" . '<div class="layui-form-item">';
$html .= "\n\t\t\t" . sprintf('<span class="help-label %s"><b>%s</b>%s</span>', empty($attrs['required']) ? '' : ' label-required-prev', $title, $substr);
$html .= "\n\t\t\t" . '<div class="layui-textarea help-checks layui-bg-gray">';
$html .= "\n\t\t\t\t" . sprintf('<!--{foreach $%s as $k=>$v}item-->', $vname);
$html .= "\n\t\t\t\t" . sprintf('<label class="think-%s label-required-null">', $type);
$html .= "\n\t\t\t\t\t" . sprintf('<!--if{if isset(%s.types) and is_array(%s.types) and in_array($k,%s.types)}-->', $this->variable, $this->variable, $this->variable);
$html .= "\n\t\t\t\t\t" . sprintf('<input value="{$k|default=\'\'}" %s checked> {$v|default=\'\'}', $this->_attrs($attrs));
$html .= "\n\t\t\t\t\t" . '<!--{else}else-->';
$html .= "\n\t\t\t\t\t" . sprintf('<input value="{$k|default=\'\'}" %s> {$v|default=\'\'}', $this->_attrs($attrs)) . "\n";
$html .= "\n\t\t\t\t\t" . '<!--{/if}if-->';
$html .= "\n\t\t\t\t" . '</label>';
$html .= "\n\t\t\t\t" . '<!--{/foreach}end-->';
$this->fields[] = $html . "\n\t\t\t</div>\n\t\t</div>";
return $this;
}
/**
* 添加单选框架字段
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $substr 字段子标题
* @param string $vname 变量名称
* @param bool $required 是否必选
* @param array $attrs 附加属性
* @return $this
*/
public function addRadioInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = []): Builder
{
return $this->addCheckInput($name, $title, $substr, $vname, $required, $attrs, 'radio');
}
/**
* 显示模板内容
* @return mixed
*/
public function fetch(array $vars = [])
{
$html = '';
$type = "{$this->type}.{$this->mode}";
if ($type === 'form.page') {
$html = $this->_buildFormPage();
} elseif ($type === 'form.modal') {
$html = $this->_buildFormModal();
}
foreach ($this->class as $k => $v) $vars[$k] = $v;
throw new HttpResponseException(display($html, $vars));
}
/**
* 生成弹层表单模板
* @return string
*/
private function _buildFormModal(): string
{
@ -402,10 +421,9 @@ class Builder
/**
* 生成页面表单模板
* @return string
*/
private function _buildFormPage(): string
{
return '';
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -24,9 +26,8 @@ use think\console\Input;
use think\console\Output;
/**
* 自定义指令基类
* 自定义指令基类.
* @class Command
* @package think\admin
*/
abstract class Command extends \think\console\Command
{
@ -43,11 +44,24 @@ abstract class Command extends \think\console\Command
protected $process;
/**
* 初始化指令变量
* @param \think\console\Input $input
* @param \think\console\Output $output
* 更新任务进度.
* @param int $total 记录总和
* @param int $count 当前记录
* @param string $message 文字描述
* @param int $backline 回退行数
* @return static
* @throws Exception
*/
public function setQueueMessage(int $total, int $count, string $message = '', int $backline = 0): Command
{
$this->queue->message($total, $count, $message, $backline);
return $this;
}
/**
* 初始化指令变量.
* @return $this
* @throws \think\admin\Exception
* @throws Exception
*/
protected function initialize(Input $input, Output $output): Command
{
@ -60,9 +74,9 @@ abstract class Command extends \think\console\Command
}
/**
* 设置失败消息并结束进程
* 设置失败消息并结束进程.
* @param string $message 消息内容
* @throws \think\admin\Exception
* @throws Exception
*/
protected function setQueueError(string $message)
{
@ -75,9 +89,9 @@ abstract class Command extends \think\console\Command
}
/**
* 设置成功消息并结束进程
* 设置成功消息并结束进程.
* @param string $message 消息内容
* @throws \think\admin\Exception
* @throws Exception
*/
protected function setQueueSuccess(string $message)
{
@ -90,12 +104,12 @@ abstract class Command extends \think\console\Command
}
/**
* 设置进度消息并继续执行
* 设置进度消息并继续执行.
* @param null|string $message 进度消息
* @param null|string $progress 进度数值
* @param integer $backline 回退行数
* @param int $backline 回退行数
* @return static
* @throws \think\admin\Exception
* @throws Exception
*/
protected function setQueueProgress(?string $message = null, ?string $progress = null, int $backline = 0): Command
{
@ -106,19 +120,4 @@ abstract class Command extends \think\console\Command
}
return $this;
}
/**
* 更新任务进度
* @param integer $total 记录总和
* @param integer $count 当前记录
* @param string $message 文字描述
* @param integer $backline 回退行数
* @return static
* @throws \think\admin\Exception
*/
public function setQueueMessage(int $total, int $count, string $message = '', int $backline = 0): Command
{
$this->queue->message($total, $count, $message, $backline);
return $this;
}
}
}

View File

@ -1,24 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
use stdClass;
use think\admin\extend\JwtExtend;
use think\admin\helper\DeleteHelper;
use think\admin\helper\FormHelper;
@ -31,32 +32,33 @@ use think\admin\service\NodeService;
use think\admin\service\QueueService;
use think\App;
use think\db\BaseQuery;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\HttpResponseException;
use think\Model;
use think\Request;
/**
* 标准控制器基类
* 标准控制器基类.
* @class Controller
* @package think\admin
*/
class Controller extends stdClass
class Controller extends \stdClass
{
/**
* 应用容器
* 应用容器.
* @var App
*/
public $app;
/**
* 请求GET参数
* 请求GET参数.
* @var array
*/
public $get = [];
/**
* 当前功能节点
* 当前功能节点.
* @var string
*/
public $node;
@ -69,19 +71,18 @@ class Controller extends stdClass
/**
* 表单CSRF验证状态
* @var boolean
* @var bool
*/
public $csrf_state = false;
/**
* 表单CSRF验证消息
* 表单CSRF验证消息.
* @var string
*/
public $csrf_message;
/**
* Constructor.
* @param App $app
*/
public function __construct(App $app)
{
@ -96,14 +97,7 @@ class Controller extends stdClass
}
/**
* 控制器初始化
*/
protected function initialize()
{
}
/**
* 返回失败的内容
* 返回失败的内容.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 返回代码
@ -114,23 +108,27 @@ class Controller extends stdClass
}
/**
* 返回成功的内容
* 返回成功的内容.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 返回代码
*/
public function success($info, $data = '{-null-}', $code = 1): void
{
if ($data === '{-null-}') $data = new stdClass();
if ($data === '{-null-}') {
$data = new \stdClass();
}
$result = ['code' => $code, 'info' => is_string($info) ? lang($info) : $info, 'data' => $data];
if (JwtExtend::isRejwt()) $result['token'] = JwtExtend::token();
if (JwtExtend::isRejwt()) {
$result['token'] = JwtExtend::token();
}
throw new HttpResponseException(json($result));
}
/**
* URL重定向
* URL重定向.
* @param string $url 跳转链接
* @param integer $code 跳转代码
* @param int $code 跳转代码
*/
public function redirect(string $url, int $code = 302): void
{
@ -138,7 +136,7 @@ class Controller extends stdClass
}
/**
* 返回视图内容
* 返回视图内容.
* @param string $tpl 模板名称
* @param array $vars 模板变量
* @param null|string $node 授权节点
@ -168,28 +166,31 @@ class Controller extends stdClass
public function assign($name, $value = ''): Controller
{
if (is_string($name)) {
$this->$name = $value;
$this->{$name} = $value;
} elseif (is_array($name)) {
foreach ($name as $k => $v) {
if (is_string($k)) $this->$k = $v;
if (is_string($k)) {
$this->{$k} = $v;
}
}
}
return $this;
}
/**
* 数据回调处理机制
* 数据回调处理机制.
* @param string $name 回调方法名称
* @param mixed $one 回调引用参数1
* @param mixed $two 回调引用参数2
* @param mixed $thr 回调引用参数3
* @return boolean
*/
public function callback(string $name, &$one = [], &$two = [], &$thr = []): bool
{
if (is_callable($name)) return call_user_func($name, $this, $one, $two, $thr);
if (is_callable($name)) {
return call_user_func($name, $this, $one, $two, $thr);
}
foreach (["_{$this->app->request->action()}{$name}", $name] as $method) {
if (method_exists($this, $method) && false === $this->$method($one, $two, $thr)) {
if (method_exists($this, $method) && $this->{$method}($one, $two, $thr) === false) {
return false;
}
}
@ -197,11 +198,15 @@ class Controller extends stdClass
}
/**
* 快捷查询逻辑器
* 控制器初始化.
*/
protected function initialize() {}
/**
* 快捷查询逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param array|string|null $input
* @return QueryHelper
* @throws \think\db\exception\DbException
* @param null|array|string $input
* @throws DbException
*/
protected function _query($dbQuery, $input = null): QueryHelper
{
@ -209,17 +214,16 @@ class Controller extends stdClass
}
/**
* 快捷分页逻辑器
* 快捷分页逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param boolean|integer $page 是否分页或指定分页
* @param boolean $display 是否渲染模板
* @param boolean|integer $total 集合分页记录数
* @param integer $limit 集合每页记录数
* @param bool|int $page 是否分页或指定分页
* @param bool $display 是否渲染模板
* @param bool|int $total 集合分页记录数
* @param int $limit 集合每页记录数
* @param string $template 模板文件名称
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function _page($dbQuery, $page = true, bool $display = true, $total = false, int $limit = 0, string $template = ''): array
{
@ -227,17 +231,17 @@ class Controller extends stdClass
}
/**
* 快捷表单逻辑器
* 快捷表单逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param string $template 模板名称
* @param string $field 指定数据主键
* @param mixed $where 额外更新条件
* @param array $data 表单扩展数据
* @return array|boolean
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array|bool
* @throws Exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function _form($dbQuery, string $template = '', string $field = '', $where = [], array $data = [])
{
@ -245,11 +249,10 @@ class Controller extends stdClass
}
/**
* 快捷输入并验证( 支持 规则 # 别名
* 快捷输入并验证( 支持 规则 # 别名 .
* @param array $rules 验证规则( 验证信息数组
* @param string|array $type 输入方式 ( post. get. )
* @param callable|null $callable 异常处理操作
* @return array
* @param array|string $type 输入方式 ( post. get. )
* @param null|callable $callable 异常处理操作
*/
protected function _vali(array $rules, $type = '', ?callable $callable = null): array
{
@ -257,13 +260,12 @@ class Controller extends stdClass
}
/**
* 快捷更新逻辑器
* 快捷更新逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param array $data 表单扩展数据
* @param string $field 数据对象主键
* @param mixed $where 额外更新条件
* @return boolean
* @throws \think\db\exception\DbException
* @throws DbException
*/
protected function _save($dbQuery, array $data = [], string $field = '', $where = []): bool
{
@ -271,12 +273,11 @@ class Controller extends stdClass
}
/**
* 快捷删除逻辑器
* 快捷删除逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param string $field 数据对象主键
* @param mixed $where 额外更新条件
* @return boolean
* @throws \think\db\exception\DbException
* @throws DbException
*/
protected function _delete($dbQuery, string $field = '', $where = []): bool
{
@ -285,8 +286,7 @@ class Controller extends stdClass
/**
* 检查表单令牌验证
* @param boolean $return 是否返回结果
* @return boolean
* @param bool $return 是否返回结果
*/
protected function _applyFormToken(bool $return = false): bool
{
@ -294,13 +294,13 @@ class Controller extends stdClass
}
/**
* 创建异步任务并返回任务编号
* 创建异步任务并返回任务编号.
* @param string $title 任务名称
* @param string $command 执行内容
* @param integer $later 延时执行时间
* @param int $later 延时执行时间
* @param array $data 任务附加数据
* @param integer $rscript 任务类型(0单例,1多例)
* @param integer $loops 循环等待时间
* @param int $rscript 任务类型(0单例,1多例)
* @param int $loops 循环等待时间
*/
protected function _queue(string $title, string $command, int $later = 0, array $data = [], int $rscript = 0, int $loops = 0)
{

View File

@ -1,27 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
/**
* 自定义数据异常
* 自定义数据异常.
* @class Exception
* @package think\admin
*/
class Exception extends \Exception
{
@ -34,10 +35,10 @@ class Exception extends \Exception
/**
* Exception constructor.
* @param string $message
* @param integer $code
* @param int $code
* @param mixed $data
*/
public function __construct($message = "", $code = 0, $data = [])
public function __construct($message = '', $code = 0, $data = [])
{
parent::__construct($message);
$this->code = $code;
@ -46,7 +47,7 @@ class Exception extends \Exception
}
/**
* 获取异常停止数据
* 获取异常停止数据.
* @return mixed
*/
public function getData()
@ -55,11 +56,11 @@ class Exception extends \Exception
}
/**
* 设置异常停止数据
* 设置异常停止数据.
* @param mixed $data
*/
public function setData($data)
{
$this->data = $data;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -27,40 +29,37 @@ use think\db\Query;
use think\Model;
/**
* 控制器助手
* 控制器助手.
* @class Helper
* @package think\admin
*/
abstract class Helper
{
/**
* 应用容器
* 应用容器.
* @var App
*/
public $app;
/**
* 控制器实例
* 控制器实例.
* @var Controller
*/
public $class;
/**
* 当前请求方式
* 当前请求方式.
* @var string
*/
public $method;
/**
* 自定输出格式
* 自定输出格式.
* @var string
*/
public $output;
/**
* Helper constructor.
* @param App $app
* @param Controller $class
*/
public function __construct(App $app, Controller $class)
{
@ -73,7 +72,7 @@ abstract class Helper
}
/**
* 实例对象反射
* 实例对象反射.
* @param array $args
* @return static
*/
@ -85,7 +84,7 @@ abstract class Helper
/**
* 获取数据库查询对象
* @param BaseQuery|Model|string $query
* @return Query|Mongo|BaseQuery
* @return BaseQuery|Mongo|Query
*/
public static function buildQuery($query)
{
@ -96,7 +95,9 @@ abstract class Helper
return self::triggerBeforeEvent(static::buildModel($query)->db());
}
}
if ($query instanceof Model) return self::triggerBeforeEvent($query->db());
if ($query instanceof Model) {
return self::triggerBeforeEvent($query->db());
}
if ($query instanceof BaseQuery && !$query->getModel()) {
// 如果是子查询,不需要挂载模型对象
if (!self::isSubquery($query->getTable())) {
@ -111,9 +112,29 @@ abstract class Helper
}
/**
* 触发查询对象执行前事件
* @param BaseQuery|Model|mixed $query
* @return BaseQuery|Model|mixed
* 动态创建模型对象
* @param mixed $name 模型名称
* @param array $data 初始数据
* @param mixed $conn 指定连接
*/
public static function buildModel(string $name, array $data = [], string $conn = ''): Model
{
if (strpos($name, '\\') !== false) {
if (class_exists($name)) {
$model = new $name($data);
if ($model instanceof Model) {
return $model;
}
}
$name = basename(str_replace('\\', '/', $name));
}
return VirtualModel::mk($name, $data, $conn);
}
/**
* 触发查询对象执行前事件.
* @param BaseQuery|mixed|Model $query
* @return BaseQuery|mixed|Model
*/
private static function triggerBeforeEvent($query)
{
@ -122,31 +143,10 @@ abstract class Helper
}
/**
* 动态创建模型对象
* @param mixed $name 模型名称
* @param array $data 初始数据
* @param mixed $conn 指定连接
* @return Model
*/
public static function buildModel(string $name, array $data = [], string $conn = ''): Model
{
if (strpos($name, '\\') !== false) {
if (class_exists($name)) {
$model = new $name($data);
if ($model instanceof Model) return $model;
}
$name = basename(str_replace('\\', '/', $name));
}
return VirtualModel::mk($name, $data, $conn);
}
/**
* 判断是否为子查询
* @param string $sql
* @return bool
* 判断是否为子查询.
*/
private static function isSubquery(string $sql): bool
{
return preg_match('/^\(?\s*select\s+/i', $sql) > 0;
}
}
}

View File

@ -1,24 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
use SplFileInfo;
use think\admin\extend\ToolsExtend;
use think\admin\service\RuntimeService;
use think\admin\support\command\Database;
@ -30,6 +31,7 @@ use think\admin\support\command\Sysmenu;
use think\admin\support\middleware\JwtSession;
use think\admin\support\middleware\MultAccess;
use think\admin\support\middleware\RbacAccess;
use think\App;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\middleware\LoadLangPack;
@ -40,16 +42,14 @@ use think\Service;
/**
* 模块注册服务
* @class Library
* @package think\admin
*/
class Library extends Service
{
/** @var \think\App */
/** @var App */
public static $sapp;
/**
* 启动服务
* @return void
*/
public function boot()
{
@ -71,7 +71,6 @@ class Library extends Service
// 请求初始化处理
$this->app->event->listen('HttpRun', function (Request $request) {
// 运行环境配置同步
RuntimeService::sync();
@ -102,15 +101,14 @@ class Library extends Service
}
/**
* 动态加载文件
* @param string $file
* 动态加载文件.
* @return mixed
*/
public static function load(string $file)
{
try {
return include $file;
} catch (\Throwable|\Error $error) {
} catch (\Error|\Throwable $error) {
trace_file($error);
throw new HttpException(500, $error->getMessage());
}
@ -118,19 +116,26 @@ class Library extends Service
/**
* 初始化服务
* @return void
*/
public function register()
{
// 动态加载全局配置
[$dir, $ext] = [$this->app->getBasePath(), $this->app->getConfigExt()];
ToolsExtend::find($dir, 2, function (SplFileInfo $info) use ($ext) {
ToolsExtend::find($dir, 2, function (\SplFileInfo $info) use ($ext) {
$info->isFile() && $info->getBasename() === "sys{$ext}" && Library::load($info->getPathname());
});
if (is_file($file = "{$dir}common{$ext}")) Library::load($file);
if (is_file($file = "{$dir}provider{$ext}")) $this->app->bind(include $file);
if (is_file($file = "{$dir}event{$ext}")) $this->app->loadEvent(include $file);
if (is_file($file = "{$dir}middleware{$ext}")) $this->app->middleware->import(include $file, 'app');
if (is_file($file = "{$dir}common{$ext}")) {
Library::load($file);
}
if (is_file($file = "{$dir}provider{$ext}")) {
$this->app->bind(include $file);
}
if (is_file($file = "{$dir}event{$ext}")) {
$this->app->loadEvent(include $file);
}
if (is_file($file = "{$dir}middleware{$ext}")) {
$this->app->middleware->import(include $file, 'app');
}
// 终端 HTTP 访问时特殊处理
if (!$this->app->runningInConsole()) {
@ -139,7 +144,9 @@ class Library extends Service
$header = ['X-Frame-Options' => $this->app->config->get('app.cors_frame') ?: 'sameorigin'];
// HTTP.CORS 跨域规则配置
if ($this->app->config->get('app.cors_on', true) && ($origin = $request->header('origin', '-')) !== '-') {
if (is_string($hosts = $this->app->config->get('app.cors_host', []))) $hosts = str2arr($hosts);
if (is_string($hosts = $this->app->config->get('app.cors_host', []))) {
$hosts = str2arr($hosts);
}
if (empty($hosts) || in_array(parse_url(strtolower($origin), PHP_URL_HOST), $hosts)) {
$headers = $this->app->config->get('app.cors_headers', 'Api-Name,Api-Type,Api-Token,Jwt-Token,User-Form-Token,User-Token,Token');
$header['Access-Control-Allow-Origin'] = $origin;
@ -152,9 +159,8 @@ class Library extends Service
// 跨域预请求状态处理
if ($request->isOptions()) {
throw new HttpResponseException(response()->code(204)->header($header));
} else {
return $next($request)->header($header);
}
return $next($request)->header($header);
});
// 初始化会话和语言包
@ -172,4 +178,4 @@ class Library extends Service
$this->app->middleware->add(RbacAccess::class, 'route');
}
}
}
}

View File

@ -1,32 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
use think\admin\helper\QueryHelper;
use think\db\Mongo;
use think\db\Query;
/**
* 基础模型类
* 基础模型类.
* @class Model
* @mixin \think\db\Query
* @package think\admin
*
* --- 静态助手调用
* @method static bool mSave(array $data = [], string $field = '', mixed $where = []) 快捷更新
* @method static bool mDelete(string $field = '', mixed $where = []) 快捷删除
* @method static bool|array mForm(string $template = '', string $field = '', mixed $where = [], array $data = []) 快捷表单
@ -36,46 +37,25 @@ use think\admin\helper\QueryHelper;
abstract class Model extends \think\Model
{
/**
* 日志类型
* @var string
*/
protected $oplogType;
/**
* 日志名称
* @var string
*/
protected $oplogName;
/**
* 日志过滤
* 日志过滤.
* @var callable
*/
public static $oplogCall;
/**
* 创建模型实例
* @template t of static
* @param mixed $data
* @return t|static
* 日志类型.
* @var string
*/
public static function mk($data = [])
{
return new static($data);
}
protected $oplogType;
/**
* 创建查询实例
* @param array $data
* @return \think\db\Query|\think\db\Mongo
* 日志名称.
* @var string
*/
public static function mq(array $data = [])
{
return Helper::buildQuery(static::mk($data)->newQuery());
}
protected $oplogName;
/**
* 调用魔术方法
* 调用魔术方法.
* @param string $method 方法名称
* @param array $args 调用参数
* @return $this|false|mixed
@ -83,10 +63,10 @@ abstract class Model extends \think\Model
public function __call($method, $args)
{
$oplogs = [
'onAdminSave' => "修改%s[%s]状态",
'onAdminUpdate' => "更新%s[%s]记录",
'onAdminInsert' => "增加%s[%s]成功",
"onAdminDelete" => "删除%s[%s]成功",
'onAdminSave' => '修改%s[%s]状态',
'onAdminUpdate' => '更新%s[%s]记录',
'onAdminInsert' => '增加%s[%s]成功',
'onAdminDelete' => '删除%s[%s]成功',
];
if (isset($oplogs[$method])) {
if ($this->oplogType && $this->oplogName) {
@ -97,16 +77,15 @@ abstract class Model extends \think\Model
sysoplog($this->oplogType, lang($oplogs[$method], [lang($this->oplogName), $changeIds]));
}
return $this;
} else {
return parent::__call($method, $args);
}
return parent::__call($method, $args);
}
/**
* 静态魔术方法
* 静态魔术方法.
* @param string $method 方法名称
* @param array $args 调用参数
* @return mixed|false|integer|QueryHelper
* @return false|int|mixed|QueryHelper
*/
public static function __callStatic($method, $args)
{
@ -114,4 +93,24 @@ abstract class Model extends \think\Model
return parent::__callStatic($method, $args);
});
}
/**
* 创建模型实例.
* @template t of static
* @param mixed $data
* @return static|t
*/
public static function mk($data = [])
{
return new static($data);
}
/**
* 创建查询实例.
* @return Mongo|Query
*/
public static function mq(array $data = [])
{
return Helper::buildQuery(static::mk($data)->newQuery());
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -27,7 +29,6 @@ use think\Service;
* 插件注册服务
*
* @class Plugin
* @package think\admin\service
*
* @method string getAppCode() static 获取插件编号
* @method string getAppName() static 获取插件名称
@ -38,7 +39,7 @@ use think\Service;
abstract class Plugin extends Service
{
/**
* 必填,插件包名
* 必填,插件包名.
* @var string
*/
protected $package = '';
@ -50,25 +51,25 @@ abstract class Plugin extends Service
protected $appCode = '';
/**
* 必填,插件名称
* 必填,插件名称.
* @var string
*/
protected $appName = '';
/**
* 可选,插件目录
* 可选,插件目录.
* @var string
*/
protected $appPath = '';
/**
* 可选,插件别名
* 可选,插件别名.
* @var string
*/
protected $appAlias = '';
/**
* 可选,命名空间
* 可选,命名空间.
* @var string
*/
protected $appSpace = '';
@ -80,14 +81,13 @@ abstract class Plugin extends Service
protected $appService = '';
/**
* 插件配置
* 插件配置.
* @var array
*/
private static $addons = [];
/**
* 自动注册插件
* @param \think\App $app
* 自动注册插件.
*/
public function __construct(App $app)
{
@ -113,7 +113,7 @@ abstract class Plugin extends Service
// 应用插件包名计算
if (empty($this->package) && ($path = $ref->getFileName())) {
for ($level = 1; $level <= 3; $level++) {
for ($level = 1; $level <= 3; ++$level) {
if (is_file($file = dirname($path, $level) . '/composer.json')) {
$this->package = json_decode(file_get_contents($file), true)['name'] ?? '';
break;
@ -123,26 +123,30 @@ abstract class Plugin extends Service
// 应用插件计算名称及别名
$attr = explode('\\', $ref->getNamespaceName());
if ($attr[0] === NodeService::space()) array_shift($attr);
if ($attr[0] === NodeService::space()) {
array_shift($attr);
}
$this->appCode = $this->appCode ?: join('-', $attr);
if ($this->appCode === $this->appAlias) $this->appAlias = '';
if ($this->appCode === $this->appAlias) {
$this->appAlias = '';
}
if (is_dir($this->appPath)) {
// 写入插件参数信息
self::$addons[$this->appCode] = [
'name' => $this->appName,
'path' => realpath($this->appPath) . DIRECTORY_SEPARATOR,
'alias' => $this->appAlias,
'space' => $this->appSpace ?: NodeService::space($this->appCode),
'name' => $this->appName,
'path' => realpath($this->appPath) . DIRECTORY_SEPARATOR,
'alias' => $this->appAlias,
'space' => $this->appSpace ?: NodeService::space($this->appCode),
'package' => $this->package,
'service' => $this->appService
'service' => $this->appService,
];
// 插件别名动态设置
if (!empty($this->appAlias) && $this->appCode !== $this->appAlias) {
Library::$sapp->config->set([
'app_map' => array_merge(Library::$sapp->config->get('app.app_map', []), [
$this->appAlias => $this->appCode
$this->appAlias => $this->appCode,
]),
], 'app');
}
@ -150,49 +154,17 @@ abstract class Plugin extends Service
}
/**
* 注册应用启动
* @return void
*/
public function boot(): void
{
}
/**
* 获取插件及安装信息
* @param ?string $code 指定插件编号
* @param boolean $append 关联安装数据
* @return ?array
*/
public static function get(?string $code = null, bool $append = false): ?array
{
// 读取插件原始信息
$data = empty($code) ? self::$addons : (self::$addons[$code] ?? null);
if (empty($data) || empty($append)) return $data;
// 关联插件安装信息
$versions = ModuleService::getLibrarys();
return empty($code) ? array_map(static function ($item) use ($versions) {
$item['install'] = $versions[$item['package']] ?? [];
if (empty($item['name'])) $item['name'] = $item['install']['name'] ?? '';
return $item;
}, $data) : $data + ['install' => $versions[$data['package']] ?? []];
}
/**
* 获取对象内部属性
* @param string $name
* @return null
* 获取对象内部属性.
*/
public function __get(string $name)
{
return $this->$name ?? '';
return $this->{$name} ?? '';
}
/**
* 静态调用方法兼容
* @param string $method
* @param array $arguments
* @return array|string|null
* @throws \think\admin\Exception
* 静态调用方法兼容.
* @return null|array|string
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
@ -216,11 +188,9 @@ abstract class Plugin extends Service
}
/**
* 魔术方法调用兼容处理
* @param string $method
* @param array $arguments
* @return array|null
* @throws \think\admin\Exception
* 魔术方法调用兼容处理.
* @return null|array
* @throws Exception
*/
public function __call(string $method, array $arguments)
{
@ -228,8 +198,36 @@ abstract class Plugin extends Service
}
/**
* 定义插件菜单
* 注册应用启动.
*/
public function boot(): void {}
/**
* 获取插件及安装信息.
* @param ?string $code 指定插件编号
* @param bool $append 关联安装数据
*/
public static function get(?string $code = null, bool $append = false): ?array
{
// 读取插件原始信息
$data = empty($code) ? self::$addons : (self::$addons[$code] ?? null);
if (empty($data) || empty($append)) {
return $data;
}
// 关联插件安装信息
$versions = ModuleService::getLibrarys();
return empty($code) ? array_map(static function ($item) use ($versions) {
$item['install'] = $versions[$item['package']] ?? [];
if (empty($item['name'])) {
$item['name'] = $item['install']['name'] ?? '';
}
return $item;
}, $data) : $data + ['install' => $versions[$data['package']] ?? []];
}
/**
* 定义插件菜单.
* @return array 一级或二级菜单
*/
abstract public static function menu(): array;
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -23,14 +25,13 @@ use think\admin\service\QueueService;
use think\App;
/**
* 任务基础类
* 任务基础类.
* @class Queue
* @package think\admin
*/
abstract class Queue
{
/**
* 应用实例
* 应用实例.
* @var App
*/
protected $app;
@ -49,8 +50,6 @@ abstract class Queue
/**
* Constructor.
* @param App $app
* @param ProcessService $process
*/
public function __construct(App $app, ProcessService $process)
{
@ -59,8 +58,7 @@ abstract class Queue
}
/**
* 初始化任务数据
* @param QueueService $queue
* 初始化任务数据.
* @return $this
*/
public function initialize(QueueService $queue): Queue
@ -70,14 +68,13 @@ abstract class Queue
}
/**
* 执行任务处理内容
* @param array $data
* @return void|string
* 执行任务处理内容.
* @return string|void
*/
abstract public function execute(array $data = []);
/**
* 设置失败的消息
* 设置失败的消息.
* @param string $message 消息内容
* @throws Exception
*/
@ -87,7 +84,7 @@ abstract class Queue
}
/**
* 设置成功的消息
* 设置成功的消息.
* @param string $message 消息内容
* @throws Exception
*/
@ -97,13 +94,13 @@ abstract class Queue
}
/**
* 更新任务进度
* @param integer $total 记录总和
* @param integer $count 当前记录
* 更新任务进度.
* @param int $total 记录总和
* @param int $count 当前记录
* @param string $message 文字描述
* @param integer $backline 回退行数
* @param int $backline 回退行数
* @return static
* @throws \think\admin\Exception
* @throws Exception
*/
protected function setQueueMessage(int $total, int $count, string $message = '', int $backline = 0): Queue
{
@ -112,16 +109,15 @@ abstract class Queue
}
/**
* 设置任务的进度
* 设置任务的进度.
* @param ?string $message 进度消息
* @param ?string $progress 进度数值
* @param integer $backline 回退行数
* @return Queue
* @throws \think\admin\Exception
* @param int $backline 回退行数
* @throws Exception
*/
protected function setQueueProgress(?string $message = null, ?string $progress = null, int $backline = 0): Queue
{
$this->queue->progress(2, $message, $progress, $backline);
return $this;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -22,21 +24,19 @@ use think\App;
use think\Container;
/**
* 自定义服务基类
* 自定义服务基类.
* @class Service
* @package think\admin
*/
abstract class Service
{
/**
* 应用实例
* 应用实例.
* @var App
*/
protected $app;
/**
* Constructor.
* @param App $app
*/
public function __construct(App $app)
{
@ -44,21 +44,19 @@ abstract class Service
$this->initialize();
}
/**
* 初始化服务
*/
protected function initialize()
{
}
/**
* 静态实例对象
* @param array $var 实例参数
* @param boolean $new 创建新实例
* @return static|mixed
* @param bool $new 创建新实例
* @return mixed|static
*/
public static function instance(array $var = [], bool $new = false)
{
return Container::getInstance()->make(static::class, $var, $new);
}
}
/**
* 初始化服务
*/
protected function initialize() {}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
@ -23,9 +25,8 @@ use think\admin\storage\LocalStorage;
use think\Container;
/**
* 文件存储引擎管理
* 文件存储引擎管理.
* @class Storage
* @package think\admin
* @method static array info($name, $safe = false, $attname = null) 文件存储信息
* @method static array set($name, $file, $safe = false, $attname = null) 储存文件
* @method static string url($name, $safe = false, $attname = null) 获取文件链接
@ -37,13 +38,26 @@ use think\Container;
*/
abstract class Storage
{
/**
* 静态访问启用.
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if (method_exists($storage = static::instance(), $method)) {
return call_user_func_array([$storage, $method], $arguments);
}
throw new Exception('method not exists: ' . get_class($storage) . "->{$method}()");
}
/**
* 实例化存储操作对象
* @param ?string $name 驱动名称
* @param ?string $class 驱动类名
* @return \think\admin\contract\StorageInterface
* @throws \think\admin\Exception
* @throws Exception
*/
public static function instance(?string $name = null, ?string $class = null): StorageInterface
{
@ -52,7 +66,9 @@ abstract class Storage
$type = ucfirst(strtolower($name ?: sysconf('storage.type|raw')));
$class = "think\\admin\\storage\\{$type}Storage";
}
if (class_exists($class)) return Container::getInstance()->make($class);
if (class_exists($class)) {
return Container::getInstance()->make($class);
}
throw new Exception("Storage driver [{$class}] does not exist.");
} catch (Exception $exception) {
throw $exception;
@ -62,26 +78,24 @@ abstract class Storage
}
/**
* 获取文件相对名称
* 获取文件相对名称.
* @param string $url 文件访问链接
* @param string $ext 文件后缀名称
* @param string $pre 文件存储前缀
* @param string $fun 名称规则方法
* @return string
*/
public static function name(string $url, string $ext = '', string $pre = '', string $fun = 'md5'): string
{
[$hah, $ext] = [$fun($url), trim($ext ?: pathinfo($url, 4), '.\\/')];
$attr = [trim($pre, '.\\/'), substr($hah, 0, 2), substr($hah, 2, 30)];
[$hah, $ext] = [$fun($url), trim($ext ?: pathinfo($url, 4), '.\/')];
$attr = [trim($pre, '.\/'), substr($hah, 0, 2), substr($hah, 2, 30)];
return trim(join('/', $attr), '/') . '.' . strtolower($ext ?: 'tmp');
}
/**
* 下载文件到本地
* 下载文件到本地.
* @param string $url 文件URL地址
* @param boolean $force 是否强制下载
* @param integer $expire 文件保留时间
* @return array
* @param bool $force 是否强制下载
* @param int $expire 文件保留时间
*/
public static function down(string $url, bool $force = false, int $expire = 0): array
{
@ -100,10 +114,9 @@ abstract class Storage
}
/**
* 获取后缀类型
* 获取后缀类型.
* @param array|string $exts 文件后缀
* @param array $mime 文件信息
* @return string
*/
public static function mime($exts, array $mime = []): string
{
@ -115,36 +128,35 @@ abstract class Storage
}
/**
* 获取所有类型
* @return array
* 获取所有类型.
*/
public static function mimes(): array
{
static $mimes = [];
if (count($mimes) > 0) return $mimes;
if (count($mimes) > 0) {
return $mimes;
}
return $mimes = include __DIR__ . '/storage/bin/mimes.php';
}
/**
* 获取存储类型
* @return array
* 获取存储类型.
*/
public static function types(): array
{
return [
'local' => lang('本地服务器存储'),
'alist' => lang('自建Alist存储'),
'qiniu' => lang('七牛云对象存储'),
'upyun' => lang('又拍云USS存储'),
'txcos' => lang('腾讯云COS存储'),
'local' => lang('本地服务器存储'),
'alist' => lang('自建Alist存储'),
'qiniu' => lang('七牛云对象存储'),
'upyun' => lang('又拍云USS存储'),
'txcos' => lang('腾讯云COS存储'),
'alioss' => lang('阿里云OSS存储'),
];
}
/**
* 使用CURL读取网络资源
* 使用CURL读取网络资源.
* @param string $url 资源地址
* @return string
*/
public static function curlGet(string $url): string
{
@ -161,28 +173,12 @@ abstract class Storage
}
/**
* 静态访问启用
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if (method_exists($storage = static::instance(), $method)) {
return call_user_func_array([$storage, $method], $arguments);
} else {
throw new Exception("method not exists: " . get_class($storage) . "->{$method}()");
}
}
/**
* 图片数据存储
* 图片数据存储.
* @param string $base64 图片内容
* @param string $prefix 保存前缀
* @param boolean $safemode 安全模式
* @param bool $safemode 安全模式
* @return array [ url => URL ]
* @throws \think\admin\Exception
* @throws Exception
*/
public static function saveImage(string $base64, string $prefix = 'image', bool $safemode = false): array
{
@ -191,13 +187,12 @@ abstract class Storage
$name = static::name($img, $ext, $prefix);
if (empty($ext) || !in_array(strtolower($ext), ['gif', 'png', 'jpg', 'jpeg'])) {
throw new Exception('内容格式异常!');
} elseif ($safemode) {
return LocalStorage::instance()->set($name, base64_decode($img), true);
} else {
return static::instance()->set($name, base64_decode($img));
}
} else {
return ['url' => $base64];
if ($safemode) {
return LocalStorage::instance()->set($name, base64_decode($img), true);
}
return static::instance()->set($name, base64_decode($img));
}
return ['url' => $base64];
}
}
}

View File

@ -1,21 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
use think\admin\extend\CodeExtend;
use think\admin\extend\HttpExtend;
use think\admin\Helper;
@ -35,9 +36,9 @@ use think\Model;
if (!function_exists('p')) {
/**
* 打印输出数据到文件
* 打印输出数据到文件.
* @param mixed $data 输出的数据
* @param boolean $new 强制替换文件
* @param bool $new 强制替换文件
* @param ?string $file 保存文件名称
* @return false|int
*/
@ -52,7 +53,6 @@ if (!function_exists('m')) {
* @param string $name 模型名称
* @param array $data 初始数据
* @param string $conn 指定连接
* @return Model
*/
function m(string $name, array $data = [], string $conn = ''): Model
{
@ -62,9 +62,7 @@ if (!function_exists('m')) {
if (!function_exists('auth')) {
/**
* 访问权限检查
* @param ?string $node
* @return boolean
* 访问权限检查.
*/
function auth(?string $node): bool
{
@ -76,9 +74,8 @@ if (!function_exists('admuri')) {
* 生成后台 URL 地址
* @param string $url 路由地址
* @param array $vars PATH 变量
* @param boolean|string $suffix 后缀
* @param boolean|string $domain 域名
* @return string
* @param bool|string $suffix 后缀
* @param bool|string $domain 域名
*/
function admuri(string $url = '', array $vars = [], $suffix = true, $domain = false): string
{
@ -87,11 +84,10 @@ if (!function_exists('admuri')) {
}
if (!function_exists('_vali')) {
/**
* 快捷输入并验证( 支持 规则 # 别名
* 快捷输入并验证( 支持 规则 # 别名 .
* @param array $rules 验证规则( 验证信息数组
* @param string|array $type 输入方式 ( post. get. )
* @param callable|null $callable 异常处理操作
* @return array
* @param array|string $type 输入方式 ( post. get. )
* @param null|callable $callable 异常处理操作
*/
function _vali(array $rules, $type = '', ?callable $callable = null): array
{
@ -100,10 +96,9 @@ if (!function_exists('_vali')) {
}
if (!function_exists('_query')) {
/**
* 快捷查询逻辑器
* 快捷查询逻辑器.
* @param BaseQuery|Model|string $dbQuery
* @param array|string|null $input
* @return QueryHelper
* @param null|array|string $input
*/
function _query($dbQuery, $input = null): QueryHelper
{
@ -112,7 +107,7 @@ if (!function_exists('_query')) {
}
if (!function_exists('sysvar')) {
/**
* 读写单次请求的内存缓存
* 读写单次请求的内存缓存.
* @param null|string $name 数据名称
* @param null|mixed $value 数据内容
* @return null|array|mixed 返回内容
@ -122,11 +117,11 @@ if (!function_exists('sysvar')) {
static $swap = [];
if ($name === '' && $value === '') {
return $swap = [];
} elseif (is_null($value)) {
return is_null($name) ? $swap : ($swap[$name] ?? null);
} else {
return $swap[$name] = $value;
}
if (is_null($value)) {
return is_null($name) ? $swap : ($swap[$name] ?? null);
}
return $swap[$name] = $value;
}
}
if (!function_exists('sysuri')) {
@ -134,26 +129,33 @@ if (!function_exists('sysuri')) {
* 生成最短 URL 地址
* @param string $url 路由地址
* @param array $vars PATH 变量
* @param boolean|string $suffix 后缀
* @param boolean|string $domain 域名
* @return string
* @param bool|string $suffix 后缀
* @param bool|string $domain 域名
*/
function sysuri(string $url = '', array $vars = [], $suffix = true, $domain = false): string
{
if (preg_match('#^(https?://|\\|/|@)#', $url)) {
if (preg_match('#^(https?://|\|/|@)#', $url)) {
return Library::$sapp->route->buildUrl($url, $vars)->suffix($suffix)->domain($domain)->build();
}
if (count($attr = $url === '' ? [] : explode('/', rtrim($url, '/'))) < 3) {
$map = [Library::$sapp->http->getName(), Library::$sapp->request->controller(), Library::$sapp->request->action(true)];
while (count($attr) < 3) array_unshift($attr, $map[2 - count($attr)] ?? 'index');
while (count($attr) < 3) {
array_unshift($attr, $map[2 - count($attr)] ?? 'index');
}
}
$attr[1] = Str::snake($attr[1]);
[$rcf, $tmp] = [Library::$sapp->config->get('route', []), uniqid('think_admin_replace_temp_vars_')];
$map = [Str::lower($rcf['default_app'] ?? ''), Str::snake($rcf['default_controller'] ?? ''), Str::lower($rcf['default_action'] ?? '')];
for ($idx = count($attr) - 1; $idx >= 0; $idx--) if ($attr[$idx] == ($map[$idx] ?: 'index')) $attr[$idx] = $tmp; else break;
for ($idx = count($attr) - 1; $idx >= 0; --$idx) {
if ($attr[$idx] == ($map[$idx] ?: 'index')) {
$attr[$idx] = $tmp;
} else {
break;
}
}
$url = Library::$sapp->route->buildUrl(join('/', $attr), $vars)->suffix($suffix)->domain($domain)->build();
$ext = is_string($suffix) ? $suffix : ($rcf['url_html_suffix'] ?? 'html');
$new = preg_replace("#/{$tmp}(\.{$ext})?#", '', $old = parse_url($url, PHP_URL_PATH) ?: '', -1, $count);
$new = preg_replace("#/{$tmp}(\\.{$ext})?#", '', $old = parse_url($url, PHP_URL_PATH) ?: '', -1, $count);
$count > 0 && $suffix && $new && $ext !== '' && $new !== Library::$sapp->request->baseUrl() && $new .= ".{$ext}";
return str_replace($old, $new ?: '/', $url);
}
@ -161,23 +163,21 @@ if (!function_exists('sysuri')) {
if (!function_exists('encode')) {
/**
* 加密 UTF8 字符串
* @param string $content
* @return string
* 加密 UTF8 字符串.
*/
function encode(string $content): string
{
[$chars, $length] = ['', strlen($string = CodeExtend::text2utf8($content))];
for ($i = 0; $i < $length; $i++) $chars .= str_pad(base_convert(strval(ord($string[$i])), 10, 36), 2, '0', 0);
for ($i = 0; $i < $length; ++$i) {
$chars .= str_pad(base_convert(strval(ord($string[$i])), 10, 36), 2, '0', 0);
}
return $chars;
}
}
if (!function_exists('decode')) {
/**
* 解密 UTF8 字符串
* @param string $content
* @return string
* 解密 UTF8 字符串.
*/
function decode(string $content): string
{
@ -191,11 +191,10 @@ if (!function_exists('decode')) {
if (!function_exists('str2arr')) {
/**
* 字符串转数组
* 字符串转数组.
* @param string $text 待转内容
* @param string $separ 分隔字符
* @param ?array $allow 限定规则
* @return array
*/
function str2arr(string $text, string $separ = ',', ?array $allow = null): array
{
@ -210,11 +209,10 @@ if (!function_exists('str2arr')) {
}
if (!function_exists('arr2str')) {
/**
* 数组转字符串
* 数组转字符串.
* @param array $data 待转数组
* @param string $separ 分隔字符
* @param ?array $allow 限定规则
* @return string
*/
function arr2str(array $data, string $separ = ',', ?array $allow = null): string
{
@ -229,8 +227,7 @@ if (!function_exists('arr2str')) {
if (!function_exists('isDebug')) {
/**
* 调试模式运行
* @return boolean
* 调试模式运行.
*/
function isDebug(): bool
{
@ -239,8 +236,7 @@ if (!function_exists('isDebug')) {
}
if (!function_exists('isOnline')) {
/**
* 产品模式运行
* @return boolean
* 产品模式运行.
*/
function isOnline(): bool
{
@ -250,58 +246,56 @@ if (!function_exists('isOnline')) {
if (!function_exists('sysconf')) {
/**
* 获取或配置系统参数
* 获取或配置系统参数.
* @param string $name 参数名称
* @param mixed $value 参数内容
* @return mixed
* @throws \think\admin\Exception
* @throws think\admin\Exception
*/
function sysconf(string $name = '', $value = null)
{
if (is_null($value) && is_string($name)) {
return SystemService::get($name);
} else {
return SystemService::set($name, $value);
}
return SystemService::set($name, $value);
}
}
if (!function_exists('sysdata')) {
/**
* JSON 数据读取与存储
* JSON 数据读取与存储.
* @param string $name 数据名称
* @param mixed $value 数据内容
* @return mixed
* @throws \think\admin\Exception
* @throws think\admin\Exception
*/
function sysdata(string $name, $value = null)
{
if (is_null($value)) {
return SystemService::getData($name);
} else {
return SystemService::setData($name, $value);
}
return SystemService::setData($name, $value);
}
}
if (!function_exists('syspath')) {
/**
* 获取文件绝对路径
* 获取文件绝对路径.
* @param string $name 文件路径
* @param ?string $root 程序根路径
* @return string
*/
function syspath(string $name = '', ?string $root = null): string
{
if (is_null($root)) $root = Library::$sapp->getRootPath();
if (is_null($root)) {
$root = Library::$sapp->getRootPath();
}
$attr = ['/' => DIRECTORY_SEPARATOR, '\\' => DIRECTORY_SEPARATOR];
return rtrim($root, '\\/') . DIRECTORY_SEPARATOR . ltrim(strtr($name, $attr), '\\/');
return rtrim($root, '\/') . DIRECTORY_SEPARATOR . ltrim(strtr($name, $attr), '\/');
}
}
if (!function_exists('sysoplog')) {
/**
* 写入系统日志
* 写入系统日志.
* @param string $action 日志行为
* @param string $content 日志内容
* @return boolean
*/
function sysoplog(string $action, string $content): bool
{
@ -310,8 +304,7 @@ if (!function_exists('sysoplog')) {
}
if (!function_exists('systoken')) {
/**
* 生成 CSRF-TOKEN 参数
* @return string
* 生成 CSRF-TOKEN 参数.
*/
function systoken(): string
{
@ -323,12 +316,11 @@ if (!function_exists('sysqueue')) {
* 注册异步处理任务
* @param string $title 任务名称
* @param string $command 执行内容
* @param integer $later 延时执行时间
* @param int $later 延时执行时间
* @param array $data 任务附加数据
* @param integer $rscript 任务类型(0单例,1多例)
* @param integer $loops 循环等待时间
* @return string
* @throws \think\admin\Exception
* @param int $rscript 任务类型(0单例,1多例)
* @param int $loops 循环等待时间
* @throws think\admin\Exception
*/
function sysqueue(string $title, string $command, int $later = 0, array $data = [], int $rscript = 1, int $loops = 0): string
{
@ -339,8 +331,6 @@ if (!function_exists('sysqueue')) {
if (!function_exists('enbase64url')) {
/**
* Base64安全URL编码
* @param string $string
* @return string
*/
function enbase64url(string $string): string
{
@ -350,8 +340,6 @@ if (!function_exists('enbase64url')) {
if (!function_exists('debase64url')) {
/**
* Base64安全URL解码
* @param string $string
* @return string
*/
function debase64url(string $string): string
{
@ -361,9 +349,7 @@ if (!function_exists('debase64url')) {
if (!function_exists('xss_safe')) {
/**
* 文本内容XSS过滤
* @param string $text
* @return string
* 文本内容XSS过滤.
*/
function xss_safe(string $text): string
{
@ -378,7 +364,7 @@ if (!function_exists('http_get')) {
* @param string $url HTTP请求URL地址
* @param array|string $query GET请求参数
* @param array $options CURL参数
* @return boolean|string
* @return bool|string
*/
function http_get(string $url, $query = [], array $options = [])
{
@ -391,7 +377,7 @@ if (!function_exists('http_post')) {
* @param string $url HTTP请求URL地址
* @param array|string $data POST请求数据
* @param array $options CURL参数
* @return boolean|string
* @return bool|string
*/
function http_post(string $url, $data, array $options = [])
{
@ -400,13 +386,13 @@ if (!function_exists('http_post')) {
}
if (!function_exists('data_save')) {
/**
* 数据增量保存
* 数据增量保存.
* @param Model|Query|string $dbQuery
* @param array $data 需要保存或更新的数据
* @param string $key 条件主键限制
* @param mixed $where 其它的where条件
* @return boolean|integer
* @throws \think\admin\Exception
* @return bool|int
* @throws think\admin\Exception
*/
function data_save($dbQuery, array $data, string $key = 'id', $where = [])
{
@ -415,11 +401,10 @@ if (!function_exists('data_save')) {
}
if (!function_exists('down_file')) {
/**
* 下载远程文件到本地
* 下载远程文件到本地.
* @param string $source 远程文件地址
* @param boolean $force 是否强制重新下载
* @param integer $expire 强制本地存储时间
* @return string
* @param bool $force 是否强制重新下载
* @param int $expire 强制本地存储时间
*/
function down_file(string $source, bool $force = false, int $expire = 0): string
{
@ -429,62 +414,63 @@ if (!function_exists('down_file')) {
if (!function_exists('trace_file')) {
/**
* 输出异常数据到文件
* @param \Exception $exception
* @return boolean
* 输出异常数据到文件.
*/
function trace_file(Exception $exception): bool
{
$path = Library::$sapp->getRuntimePath() . 'trace';
if (!is_dir($path)) mkdir($path, 0777, true);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$name = substr($exception->getFile(), strlen(syspath()));
$file = $path . DIRECTORY_SEPARATOR . date('Ymd_His_') . strtr($name, ['/' => '.', '\\' => '.']);
$json = json_encode($exception instanceof \think\admin\Exception ? $exception->getData() : [], 64 | 128 | 256);
$json = json_encode($exception instanceof think\admin\Exception ? $exception->getData() : [], 64 | 128 | 256);
$class = get_class($exception);
return false !== file_put_contents($file,
"[CODE] {$exception->getCode()}" . PHP_EOL .
"[INFO] {$exception->getMessage()}" . PHP_EOL .
($exception instanceof \think\admin\Exception ? "[DATA] {$json}" . PHP_EOL : '') .
"[FILE] {$class} in {$name} line {$exception->getLine()}" . PHP_EOL .
"[TIME] " . date('Y-m-d H:i:s') . PHP_EOL . PHP_EOL .
'[TRACE]' . PHP_EOL . $exception->getTraceAsString()
);
return file_put_contents(
$file,
"[CODE] {$exception->getCode()}" . PHP_EOL
. "[INFO] {$exception->getMessage()}" . PHP_EOL
. ($exception instanceof think\admin\Exception ? "[DATA] {$json}" . PHP_EOL : '')
. "[FILE] {$class} in {$name} line {$exception->getLine()}" . PHP_EOL
. '[TIME] ' . date('Y-m-d H:i:s') . PHP_EOL . PHP_EOL
. '[TRACE]' . PHP_EOL . $exception->getTraceAsString()
) !== false;
}
}
if (!function_exists('format_bytes')) {
/**
* 文件字节单位转换
* @param string|integer $size
* @return string
* 文件字节单位转换.
* @param int|string $size
*/
function format_bytes($size): string
{
if (is_numeric($size)) {
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
for ($i = 0; $size >= 1024 && $i < 4; ++$i) {
$size /= 1024;
}
return round($size, 2) . ' ' . $units[$i];
} else {
return $size;
}
return $size;
}
}
if (!function_exists('format_datetime')) {
/**
* 日期格式标准输出
* 日期格式标准输出.
* @param int|string $datetime 输入日期
* @param string $format 输出格式
* @return string
*/
function format_datetime($datetime, string $format = 'Y年m月d日 H:i:s'): string
{
if (empty($datetime)) {
return '-';
} elseif (is_numeric($datetime)) {
return date(lang($format), intval($datetime));
} elseif ($timestamp = strtotime((string)$datetime)) {
return date(lang($format), $timestamp);
} else {
return (string)$datetime;
}
if (is_numeric($datetime)) {
return date(lang($format), intval($datetime));
}
if ($timestamp = strtotime((string)$datetime)) {
return date(lang($format), $timestamp);
}
return (string)$datetime;
}
}
}

View File

@ -1,99 +1,91 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\contract;
/**
* 文件存储标准接口
* 文件存储标准接口.
* @class StorageInterface
* @package think\admin\contract
*/
interface StorageInterface
{
/**
* 上传文件内容
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array;
/**
* 读取文件内容
* 读取文件内容.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string;
/**
* 删除存储文件
* 删除存储文件.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool;
/**
* 判断是否存在
* 判断是否存在.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool;
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string;
/**
* 获取存储路径
* 获取存储路径.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string;
/**
* 获取文件信息
* 获取文件信息.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array;
/**
* 获取上传地址
* @return string
*/
public function upload(): string;
/**
* 获取存储区域
* @return array
*/
public static function region(): array;
}
}

View File

@ -14,7 +14,23 @@
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\contract;
@ -23,19 +39,18 @@ use think\App;
use think\Container;
/**
* 文件存储公共属性
* 文件存储公共属性.
* @class StorageUsageTrait
* @package think\admin\contract
*/
trait StorageUsageTrait
{
/**
* @var \think\App $app
* @var App
*/
protected $app;
/**
* 链接类型
* 链接类型.
* @var string
*/
protected $link;
@ -47,9 +62,8 @@ trait StorageUsageTrait
protected $domain;
/**
* 存储器构造方法
* @param \think\App $app
* @throws \think\admin\Exception
* 存储器构造方法.
* @throws Exception
*/
public function __construct(App $app)
{
@ -59,38 +73,51 @@ trait StorageUsageTrait
}
/**
* 自定义初始化方法
* @return void
* 重构后兼容处理.
* @return array|string
* @throws Exception
*/
protected function init()
public function __call(string $method, array $arguments)
{
if (strtolower($method) === 'builduploadtoken') {
if (method_exists($this, 'token')) {
return $this->token(...$arguments);
}
}
// 调用方法异常处理
$class = class_basename(static::class);
throw new Exception("method not exists: {$class}->{$method}()");
}
/**
* 获取对象实例
* 获取对象实例.
* @return static
*/
public static function instance()
{
/** @var \think\admin\contract\StorageInterface */
/* @var \think\admin\contract\StorageInterface */
return Container::getInstance()->make(static::class);
}
/**
* 自定义初始化方法.
*/
protected function init() {}
/**
* 获取下载链接后缀
* @param null|string $attname 下载名称
* @param null|string $filename 文件名称
* @return string
*/
protected function getSuffix(?string $attname = null, ?string $filename = null): string
{
[$class, $suffix] = [class_basename(get_class($this)), ''];
if (is_string($filename) && stripos($this->link, 'compress') !== false) {
$compress = [
'LocalStorage' => '',
'QiniuStorage' => '?imageslim',
'UpyunStorage' => '!/format/webp',
'TxcosStorage' => '?imageMogr2/format/webp',
'LocalStorage' => '',
'QiniuStorage' => '?imageslim',
'UpyunStorage' => '!/format/webp',
'TxcosStorage' => '?imageMogr2/format/webp',
'AliossStorage' => '?x-oss-process=image/format,webp',
];
$extens = strtolower(pathinfo($this->delSuffix($filename), PATHINFO_EXTENSION));
@ -107,9 +134,8 @@ trait StorageUsageTrait
}
/**
* 获取文件基础名称
* 获取文件基础名称.
* @param string $name 文件名称
* @return string
*/
protected function delSuffix(string $name): string
{
@ -121,23 +147,4 @@ trait StorageUsageTrait
}
return $name;
}
/**
* 重构后兼容处理
* @param string $method
* @param array $arguments
* @return array|string
* @throws \think\admin\Exception
*/
public function __call(string $method, array $arguments)
{
if (strtolower($method) === 'builduploadtoken') {
if (method_exists($this, 'token')) {
return $this->token(...$arguments);
}
}
// 调用方法异常处理
$class = class_basename(static::class);
throw new Exception("method not exists: {$class}->{$method}()");
}
}
}

View File

@ -1,27 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\contract;
/**
* 流协议接口
* 流协议接口.
* @class StreamInterface
* @package think\admin\contract
*/
interface StreamInterface
{
@ -54,8 +55,7 @@ interface StreamInterface
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool;
/**
* @param int $count
* @return string|false
* @return false|string
*/
public function stream_read(int $count);
@ -77,9 +77,7 @@ interface StreamInterface
public function unlink(string $path): bool;
/**
* @param string $path
* @param integer $flags
* @return array|false
*/
public function url_stat(string $path, int $flags);
}
}

View File

@ -1,34 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
/**
* 随机数码管理扩展
* 随机数码管理扩展.
* @class CodeExtend
* @package think\admin\extend
*/
class CodeExtend
{
/**
* 生成 UUID 编码
* @return string
*/
public static function uuid(): string
{
@ -40,48 +39,59 @@ class CodeExtend
/**
* 生成随机编码
* @param integer $size 编码长度
* @param integer $type 编码类型(1纯数字,2纯字母,3数字字母)
* @param int $size 编码长度
* @param int $type 编码类型(1纯数字,2纯字母,3数字字母)
* @param string $prefix 编码前缀
* @return string
*/
public static function random(int $size = 10, int $type = 1, string $prefix = ''): string
{
$numbs = '0123456789';
$chars = 'abcdefghijklmnopqrstuvwxyz';
if ($type === 1) $chars = $numbs;
if ($type === 3) $chars = "{$numbs}{$chars}";
if ($type === 1) {
$chars = $numbs;
}
if ($type === 3) {
$chars = "{$numbs}{$chars}";
}
$code = $prefix . $chars[rand(1, strlen($chars) - 1)];
while (strlen($code) < $size) $code .= $chars[rand(0, strlen($chars) - 1)];
while (strlen($code) < $size) {
$code .= $chars[rand(0, strlen($chars) - 1)];
}
return $code;
}
/**
* 生成日期编码
* @param integer $size 编码长度
* @param int $size 编码长度
* @param string $prefix 编码前缀
* @return string
*/
public static function uniqidDate(int $size = 16, string $prefix = ''): string
{
if ($size < 14) $size = 14;
if ($size < 14) {
$size = 14;
}
$code = $prefix . date('Ymd') . (date('H') + date('i')) . date('s');
while (strlen($code) < $size) $code .= rand(0, 9);
while (strlen($code) < $size) {
$code .= rand(0, 9);
}
return $code;
}
/**
* 生成数字编码
* @param integer $size 编码长度
* @param int $size 编码长度
* @param string $prefix 编码前缀
* @return string
*/
public static function uniqidNumber(int $size = 12, string $prefix = ''): string
{
$time = strval(time());
if ($size < 10) $size = 10;
if ($size < 10) {
$size = 10;
}
$code = $prefix . (intval($time[0]) + intval($time[1])) . substr($time, 2) . rand(0, 9);
while (strlen($code) < $size) $code .= rand(0, 9);
while (strlen($code) < $size) {
$code .= rand(0, 9);
}
return $code;
}
@ -89,23 +99,26 @@ class CodeExtend
* 文本转码
* @param string $text 文本内容
* @param string $target 目标编码
* @return string
*/
public static function text2utf8(string $text, string $target = 'UTF-8'): string
{
[$first2, $first4] = [substr($text, 0, 2), substr($text, 0, 4)];
if ($first4 === chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF)) $ft = 'UTF-32BE';
elseif ($first4 === chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00)) $ft = 'UTF-32LE';
elseif ($first2 === chr(0xFE) . chr(0xFF)) $ft = 'UTF-16BE';
elseif ($first2 === chr(0xFF) . chr(0xFE)) $ft = 'UTF-16LE';
if ($first4 === chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF)) {
$ft = 'UTF-32BE';
} elseif ($first4 === chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00)) {
$ft = 'UTF-32LE';
} elseif ($first2 === chr(0xFE) . chr(0xFF)) {
$ft = 'UTF-16BE';
} elseif ($first2 === chr(0xFF) . chr(0xFE)) {
$ft = 'UTF-16LE';
}
return mb_convert_encoding($text, $target, $ft ?? mb_detect_encoding($text));
}
/**
* 数据加密处理
* 数据加密处理.
* @param mixed $data 加密数据
* @param string $skey 安全密钥
* @return string
*/
public static function encrypt($data, string $skey): string
{
@ -115,7 +128,7 @@ class CodeExtend
}
/**
* 数据解密处理
* 数据解密处理.
* @param string $data 解密数据
* @param string $skey 安全密钥
* @return mixed
@ -129,7 +142,6 @@ class CodeExtend
/**
* Base64Url 安全编码
* @param string $text 待加密文本
* @return string
*/
public static function enSafe64(string $text): string
{
@ -139,17 +151,15 @@ class CodeExtend
/**
* Base64Url 安全解码
* @param string $text 待解密文本
* @return string
*/
public static function deSafe64(string $text): string
{
return base64_decode(str_pad(strtr($text, '-_', '+/'), (int) (ceil(strlen($text) / 4) * 4), '='));
return base64_decode(str_pad(strtr($text, '-_', '+/'), (int)(ceil(strlen($text) / 4) * 4), '='));
}
/**
* 压缩数据对象
* @param mixed $data
* @return string
*/
public static function enzip($data): string
{
@ -158,11 +168,10 @@ class CodeExtend
/**
* 解压数据对象
* @param string $string
* @return mixed
*/
public static function dezip(string $string)
{
return unserialize(gzuncompress(static::deSafe64($string)));
}
}
}

View File

@ -1,56 +1,57 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
/**
* 数据处理扩展
* 数据处理扩展.
* @class DataExtend
* @package think\admin\extend
*/
class DataExtend
{
/**
* 二维数组转多维数据树
* 二维数组转多维数据树.
* @param array $list 待处理数据
* @param string $ckey 自己的主键
* @param string $pkey 上级的主键
* @param string $chil 子数组名称
* @return array
*/
public static function arr2tree(array $list, string $ckey = 'id', string $pkey = 'pid', string $chil = 'sub'): array
{
[$tree, $list] = [[], array_column($list, null, $ckey)];
foreach ($list as $it) isset($list[$it[$pkey]]) ? $list[$it[$pkey]][$chil][] = &$list[$it[$ckey]] : $tree[] = &$list[$it[$ckey]];
foreach ($list as $it) {
isset($list[$it[$pkey]]) ? $list[$it[$pkey]][$chil][] = &$list[$it[$ckey]] : $tree[] = &$list[$it[$ckey]];
}
return $tree;
}
/**
* 二维数组转数据树表
* 二维数组转数据树表.
* @param array $list 待处理数据
* @param string $ckey 自己的主键
* @param string $pkey 上级的主键
* @param string $path 当前 PATH
* @return array
*/
public static function arr2table(array $list, string $ckey = 'id', string $pkey = 'pid', string $path = 'path'): array
{
$build = static function (array $nodes, callable $build, array &$data = [], string $parent = '') use ($ckey, $pkey, $path) {
$build = static function (array $nodes, callable $build, array &$data = [], string $parent = '') use ($ckey, $path) {
foreach ($nodes as $node) {
$subs = $node['sub'] ?? [];
unset($node['sub']);
@ -60,11 +61,15 @@ class DataExtend
$node['spl'] = str_repeat('ㅤ├ㅤ', $node['spt']);
$node['sps'] = ",{$node[$ckey]},";
array_walk_recursive($subs, static function ($val, $key) use ($ckey, &$node) {
if ($key === $ckey) $node['sps'] .= "{$val},";
if ($key === $ckey) {
$node['sps'] .= "{$val},";
}
});
$node['spp'] = arr2str(str2arr(strtr($parent . $node['sps'], '-', ',')));
$data[] = $node;
if (empty($subs)) continue;
if (empty($subs)) {
continue;
}
$build($subs, $build, $data, $node[$path]);
}
return $data;
@ -73,19 +78,20 @@ class DataExtend
}
/**
* 获取数据树子ID集合
* 获取数据树子ID集合.
* @param array $list 数据列表
* @param mixed $value 起始有效ID值
* @param string $ckey 当前主键ID名称
* @param string $pkey 上级主键ID名称
* @return array
*/
public static function getArrSubIds(array $list, $value = 0, string $ckey = 'id', string $pkey = 'pid'): array
{
$ids = [intval($value)];
foreach ($list as $vo) if (intval($vo[$pkey]) > 0 && intval($vo[$pkey]) === intval($value)) {
$ids = array_merge($ids, static::getArrSubIds($list, intval($vo[$ckey]), $ckey, $pkey));
foreach ($list as $vo) {
if (intval($vo[$pkey]) > 0 && intval($vo[$pkey]) === intval($value)) {
$ids = array_merge($ids, static::getArrSubIds($list, intval($vo[$ckey]), $ckey, $pkey));
}
}
return $ids;
}
}
}

View File

@ -1,44 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
/**
* 导出 CSV 文件扩展
* 导出 CSV 文件扩展.
* @class ExcelExtend
* @deprecated 改用 JavaScript
* @package think\admin\extend
*/
class ExcelExtend
{
/**
* 设置写入 CSV 文件头部
* 设置写入 CSV 文件头部.
* @param string $name 导出文件名称
* @param array $headers 表格头部(一维数组)
*/
public static function header(string $name, array $headers): void
{
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=" . iconv('utf-8', 'gbk//TRANSLIT', $name));
header('Content-Disposition: attachment; filename=' . iconv('utf-8', 'gbk//TRANSLIT', $name));
$handle = fopen('php://output', 'w');
foreach ($headers as $key => $value) {
$headers[$key] = iconv("utf-8", "gbk//TRANSLIT", $value);
$headers[$key] = iconv('utf-8', 'gbk//TRANSLIT', $value);
}
fputcsv($handle, $headers);
if (is_resource($handle)) {
@ -47,7 +47,7 @@ class ExcelExtend
}
/**
* 设置写入CSV文件内容
* 设置写入CSV文件内容.
* @param array $list 数据列表(二维数组)
* @param array $rules 数据规则(一维数组)
*/
@ -67,15 +67,16 @@ class ExcelExtend
}
/**
* 根据数组key查询(可带点规则)
* 根据数组key查询(可带点规则).
* @param array $data 数据
* @param string $rule 规则,如: order.order_no
* @return string
*/
public static function parseKeyDotValue(array $data, string $rule): string
{
[$temp, $attr] = [$data, explode('.', trim($rule, '.'))];
while ($key = array_shift($attr)) $temp = $temp[$key] ?? $temp;
while ($key = array_shift($attr)) {
$temp = $temp[$key] ?? $temp;
}
return (is_string($temp) || is_numeric($temp)) ? @iconv('utf-8', 'gbk//TRANSLIT', "{$temp}") : '';
}
}
}

View File

@ -1,45 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
use think\admin\Exception;
/**
* 网站 ICO 文件生成工具
* 网站 ICO 文件生成工具.
* @class FaviconExtend
* @package think\admin\extend
*/
class FaviconExtend
{
/**
* 转换后的 BMP 图像
* 转换后的 BMP 图像.
* @var array
*/
private $images = [];
/**
* Constructor - 创建一个新的 ICO 生成器
* Constructor - 创建一个新的 ICO 生成器.
* @param ?string $file 源图像文件的路径
* @param array $size 图片文件尺寸 [W1,H1]
* @throws \think\admin\Exception
* @throws Exception
*/
function __construct(?string $file = null, array $size = [])
public function __construct(?string $file = null, array $size = [])
{
$functions = [
'imagesx',
@ -54,8 +55,10 @@ class FaviconExtend
'imagealphablending',
];
foreach ($functions as $function) if (!function_exists($function)) {
throw new Exception(lang('Required %s function not found.', [$function]));
foreach ($functions as $function) {
if (!function_exists($function)) {
throw new Exception(lang('Required %s function not found.', [$function]));
}
}
if (is_string($file)) {
@ -64,11 +67,11 @@ class FaviconExtend
}
/**
* 添加图像到生成器中
* 添加图像到生成器中.
*
* @param string $file 图像文件路径
* @param array $size 图像文件尺寸
* @throws \think\admin\Exception
* @throws Exception
*/
public function addImage(string $file, array $size = []): FaviconExtend
{
@ -86,7 +89,7 @@ class FaviconExtend
imagesavealpha($image, true);
[$sourceWidth, $sourceHeight] = [imagesx($im), imagesy($im)];
if (false === imagecopyresampled($image, $im, 0, 0, 0, 0, $width, $height, $sourceWidth, $sourceHeight)) {
if (imagecopyresampled($image, $im, 0, 0, 0, 0, $width, $height, $sourceWidth, $sourceHeight) === false) {
throw new Exception(lang('Parse and process picture Failed.'));
}
$this->addImageData($image);
@ -94,10 +97,9 @@ class FaviconExtend
}
/**
* ICO 内容写入到文件
* ICO 内容写入到文件.
*
* @param string $file 写入文件路径
* @return boolean
*/
public function saveIco(string $file): bool
{
@ -107,7 +109,7 @@ class FaviconExtend
if (false === ($fh = fopen($file, 'w'))) {
return false;
}
if (false === (fwrite($fh, $data))) {
if (fwrite($fh, $data) === false) {
fclose($fh);
return false;
}
@ -116,7 +118,7 @@ class FaviconExtend
}
/**
* 生成并获取 ICO 图像数据
* 生成并获取 ICO 图像数据.
*/
private function getIcoData()
{
@ -137,14 +139,15 @@ class FaviconExtend
}
/**
* GD 图像转为 BMP 格式
* GD 图像转为 BMP 格式.
* @param mixed $im
*/
private function addImageData($im)
{
[$width, $height] = [imagesx($im), imagesy($im)];
[$pixelData, $opacityData, $opacityValue] = [[], [], 0];
for ($y = $height - 1; $y >= 0; $y--) {
for ($x = 0; $x < $width; $x++) {
for ($y = $height - 1; $y >= 0; --$y) {
for ($x = 0; $x < $width; ++$x) {
$color = imagecolorat($im, $x, $y);
$alpha = ($color & 0x7F000000) >> 24;
$alpha = (1 - ($alpha / 127)) * 255;
@ -170,26 +173,30 @@ class FaviconExtend
$imageHeaderSize = 40;
$colorMaskSize = $width * $height * 4;
$opacityMaskSize = (ceil($width / 32) * 4) * $height;
$data = pack('VVVvvVVVVVV', 40, $width, ($height * 2), 1, 32, 0, 0, 0, 0, 0, 0);
foreach ($pixelData as $color) $data .= pack('V', $color);
foreach ($opacityData as $opacity) $data .= pack('N', $opacity);
$data = pack('VVVvvVVVVVV', 40, $width, $height * 2, 1, 32, 0, 0, 0, 0, 0, 0);
foreach ($pixelData as $color) {
$data .= pack('V', $color);
}
foreach ($opacityData as $opacity) {
$data .= pack('N', $opacity);
}
$this->images[] = [
'data' => $data,
'size' => $imageHeaderSize + $colorMaskSize + $opacityMaskSize,
'data' => $data,
'size' => $imageHeaderSize + $colorMaskSize + $opacityMaskSize,
'width' => $width, 'height' => $height,
'pixel' => 32, 'colors' => 0,
];
}
/**
* 读取图片资源
* 读取图片资源.
* @param string $file 文件路径
* @return false|resource|\GdImage
* @return false|\GdImage|resource
*/
private function loadImageFile(string $file)
{
if (false === getimagesize($file)) {
if (getimagesize($file) === false) {
return false;
}
if (false === ($data = file_get_contents($file))) {
@ -201,4 +208,4 @@ class FaviconExtend
unset($data);
return $image;
}
}
}

View File

@ -1,27 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
/**
* CURL模拟请求扩展
* CURL模拟请求扩展.
* @class HttpExtend
* @package think\admin\extend
*/
class HttpExtend
{
@ -30,7 +31,7 @@ class HttpExtend
* @param string $location HTTP请求地址
* @param array|string $data GET请求参数
* @param array $options CURL请求参数
* @return boolean|string
* @return bool|string
*/
public static function get(string $location, $data = [], array $options = [])
{
@ -43,7 +44,7 @@ class HttpExtend
* @param string $location HTTP请求地址
* @param array|string $data POST请求数据
* @param array $options CURL请求参数
* @return boolean|string
* @return bool|string
*/
public static function post(string $location, $data = [], array $options = [])
{
@ -58,8 +59,8 @@ class HttpExtend
* @param array $file 提交文件 [field,name,type,content]
* @param array $header 请求头部信息,默认带 Content-type
* @param string $method 模拟请求的方式 [GET,POST,PUT]
* @param boolean $returnHeader 是否返回头部信息
* @return boolean|string
* @param bool $returnHeader 是否返回头部信息
* @return bool|string
*/
public static function submit(string $url, array $data = [], array $file = [], array $header = [], string $method = 'POST', bool $returnHeader = true)
{
@ -67,14 +68,16 @@ class HttpExtend
foreach ($data as $key => $value) {
$line[] = "--{$boundary}";
$line[] = "Content-Disposition: form-data; name=\"{$key}\"";
$line[] = "";
$line[] = '';
$line[] = $value;
}
if (is_array($file) && isset($file['field']) && isset($file['name'])) {
if (is_array($file) && isset($file['field'], $file['name'])) {
$line[] = "--{$boundary}";
$line[] = "Content-Disposition: form-data; name=\"{$file['field']}\"; filename=\"{$file['name']}\"";
if (isset($file['type'])) $line[] = "Content-Type: \"{$file['type']}\"";
$line[] = "";
if (isset($file['type'])) {
$line[] = "Content-Type: \"{$file['type']}\"";
}
$line[] = '';
$line[] = $file['content'];
}
$line[] = "--{$boundary}--";
@ -87,7 +90,7 @@ class HttpExtend
* @param string $method 模拟请求方式
* @param string $location 模拟请求地址
* @param array $options 请求参数[headers,query,data,cookie,cookie_file,timeout,returnHeader]
* @return boolean|string
* @return bool|string
*/
public static function request(string $method, string $location, array $options = [])
{
@ -139,8 +142,10 @@ class HttpExtend
// 自定义扩展参数配置,二维数组内每个单元为一个设置语句,格式如下:
// $setopt = [ [CURLOPT_URL, $location], [CURLOPT_AUTOREFERER, true], ...];
if (isset($options['setopt']) && is_array($options['setopt'])) {
foreach ($options['setopt'] as $value) if (is_array($value)) {
curl_setopt($curl, ...$value);
foreach ($options['setopt'] as $value) {
if (is_array($value)) {
curl_setopt($curl, ...$value);
}
}
}
curl_setopt($curl, CURLOPT_URL, $location);
@ -155,22 +160,21 @@ class HttpExtend
}
/**
* 获取浏览器代理信息
* @return string
* 获取浏览器代理信息.
*/
private static function getUserAgent(): string
{
$agents = [
"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11',
'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0',
'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
];
return $agents[array_rand($agents)];
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
@ -23,9 +25,8 @@ use think\admin\Storage;
use think\admin\storage\LocalStorage;
/**
* 拼图拖拽验证器
* 拼图拖拽验证器.
* @class ImageVerify
* @package think\admin\extend
*/
class ImageVerify
{
@ -37,14 +38,16 @@ class ImageVerify
// 浮层图宽高
private $picWidth = 100;
private $picHeight = 100;
// 目标图宽高
private $dstWidth = 600;
private $dstHeight = 300;
/**
* 验证器构造方法
* 验证器构造方法.
* @param string $image 原始图片
* @param array $options 配置参数
*/
@ -52,18 +55,20 @@ class ImageVerify
{
if (!empty($options)) {
foreach ($options as $k => $v) {
if (isset($this->$k)) $this->$k = $v;
if (isset($this->{$k})) {
$this->{$k} = $v;
}
}
}
$this->srcImage = $image;
}
/**
* 生成图片拼图
* 生成图片拼图.
* @param string $image 原始图片
* @param integer $time 缓存时间
* @param integer $diff 容错数值
* @param integer $retry 容错次数
* @param int $time 缓存时间
* @param int $diff 容错数值
* @param int $retry 容错次数
* @return array [code, bgimg, water]
*/
public static function render(string $image, int $time = 1800, int $diff = 10, int $retry = 3): array
@ -76,16 +81,18 @@ class ImageVerify
}
/**
* 在线验证是否通过
* 在线验证是否通过.
* @param string $code 验证码编码
* @param string $value 待验证数值
* @param boolean $clear 验证成功清理
* @return integer [ -1:需要刷新, 0:验证失败, 1:验证成功 ]
* @param bool $clear 验证成功清理
* @return int [ -1:需要刷新, 0:验证失败, 1:验证成功 ]
*/
public static function verify(string $code, string $value, bool $clear = false): int
{
$cache = Library::$sapp->cache->get($code);
if (empty($cache['range']) || empty($cache['retry'])) return -1;
if (empty($cache['range']) || empty($cache['retry'])) {
return -1;
}
if ($cache['range'][0] <= $value && $value <= $cache['range'][1]) {
$clear && Library::$sapp->cache->delete($code);
return 1;
@ -103,10 +110,10 @@ class ImageVerify
}
/**
* 剧中裁剪图片
* 剧中裁剪图片.
* @param string $image 图片资源
* @param integer $width 目标宽度
* @param integer $height 目标高度
* @param int $width 目标宽度
* @param int $height 目标高度
* @return \GdImage|resource
*/
public static function cover(string $image, int $width, int $height)
@ -114,7 +121,9 @@ class ImageVerify
// 读取缓存返回图片资源
$local = LocalStorage::instance();
$name = Storage::name(join('#', func_get_args()), 'png', 'cache');
if ($local->has($name, true)) return imageCreateFromString($local->get($name, true));
if ($local->has($name, true)) {
return imagecreatefromstring($local->get($name, true));
}
// 计算图片尺寸裁剪坐标
[$w, $h] = getimagesize($image);
if ($w > $h) {
@ -124,8 +133,8 @@ class ImageVerify
} else {
[$_sw, $_sh, $_sx, $_sy] = [$w, $h, 0, 0];
}
$newim = imageCreateTrueColor($width, $height);
$srcim = imageCreateFromString(file_get_contents($image));
$newim = imagecreatetruecolor($width, $height);
$srcim = imagecreatefromstring(file_get_contents($image));
imagecopyresampled($newim, $srcim, 0, 0, $_sx, $_sy, $width, $height, $_sw, $_sh);
imagedestroy($srcim);
// 缓存图片内容
@ -137,7 +146,7 @@ class ImageVerify
}
/**
* 创建背景图和浮层图、浮层图X坐标
* 创建背景图和浮层图、浮层图X坐标.
* @return array [point, bgimg, water]
*/
public function create(): array
@ -146,9 +155,9 @@ class ImageVerify
$dstim = $this->cover($this->srcImage, $this->dstWidth, $this->dstHeight);
// 生成透明底浮层图画布
$watim = imageCreateTrueColor($this->picWidth, $this->dstHeight);
imageSaveAlpha($watim, true) && imageAlphaBlending($watim, false);
imageFill($watim, 0, 0, imageColorAllocateAlpha($watim, 255, 255, 255, 127));
$watim = imagecreatetruecolor($this->picWidth, $this->dstHeight);
imagesavealpha($watim, true) && imagealphablending($watim, false);
imagefill($watim, 0, 0, imagecolorallocatealpha($watim, 255, 255, 255, 127));
// 随机位置
$srcX1 = mt_rand(150, $this->dstWidth - $this->picWidth); // 水印位于大图X坐标
@ -162,48 +171,48 @@ class ImageVerify
// 水印边框颜色
$broders = [
imageColorAllocateAlpha($dstim, 250, 100, 0, 50),
imageColorAllocateAlpha($dstim, 250, 0, 100, 50),
imageColorAllocateAlpha($dstim, 100, 0, 250, 50),
imageColorAllocateAlpha($dstim, 100, 250, 0, 50),
imageColorAllocateAlpha($dstim, 0, 250, 100, 50),
imagecolorallocatealpha($dstim, 250, 100, 0, 50),
imagecolorallocatealpha($dstim, 250, 0, 100, 50),
imagecolorallocatealpha($dstim, 100, 0, 250, 50),
imagecolorallocatealpha($dstim, 100, 250, 0, 50),
imagecolorallocatealpha($dstim, 0, 250, 100, 50),
];
shuffle($broders);
$c1 = array_pop($broders);
$c2 = array_pop($broders);
$gray = imageColorAllocateAlpha($dstim, 0, 0, 0, 80);
$blue = imageColorAllocateAlpha($watim, 0, 100, 250, 50);
$gray = imagecolorallocatealpha($dstim, 0, 0, 0, 80);
$blue = imagecolorallocatealpha($watim, 0, 100, 250, 50);
// 取原图像素颜色,生成浮层图
$waters = $this->withWaterPoint();
for ($i = 0; $i < $this->picHeight; $i++) {
for ($j = 0; $j < $this->picWidth; $j++) {
for ($i = 0; $i < $this->picHeight; ++$i) {
for ($j = 0; $j < $this->picWidth; ++$j) {
if ($waters[$i][$j] === 1) {
if (
empty($waters[$i - 1][$j - 1]) || empty($waters[$i - 2][$j - 2]) ||
empty($waters[$i + 1][$j + 1]) || empty($waters[$i + 2][$j + 2])
empty($waters[$i - 1][$j - 1]) || empty($waters[$i - 2][$j - 2])
|| empty($waters[$i + 1][$j + 1]) || empty($waters[$i + 2][$j + 2])
) {
imagesetpixel($watim, $j, $srcY1 + $i, $blue);
} else {
imagesetpixel($watim, $j, $srcY1 + $i, ImageColorAt($dstim, $srcX1 + $j, $srcY1 + $i));
imagesetpixel($watim, $j, $srcY1 + $i, imagecolorat($dstim, $srcX1 + $j, $srcY1 + $i));
}
}
}
}
// 在原图挖坑,打上灰色水印
for ($i = 0; $i < $this->picHeight; $i++) {
for ($j = 0; $j < $this->picWidth; $j++) {
for ($i = 0; $i < $this->picHeight; ++$i) {
for ($j = 0; $j < $this->picWidth; ++$j) {
if ($waters[$i][$j] === 1) {
if (
empty($waters[$i - 1][$j - 1]) ||
empty($waters[$i - 2][$j - 2]) ||
empty($waters[$i + 1][$j + 1]) ||
empty($waters[$i + 2][$j + 2])
empty($waters[$i - 1][$j - 1])
|| empty($waters[$i - 2][$j - 2])
|| empty($waters[$i + 1][$j + 1])
|| empty($waters[$i + 2][$j + 2])
) {
imagesetpixel($dstim, $srcX1 + $j, $srcY1 + $i, $c1);
// 去除第二个干扰水印
// imagesetpixel($dstim, $srcX2 + $j, $srcY2 + $i, $c2);
// 去除第二个干扰水印
// imagesetpixel($dstim, $srcX2 + $j, $srcY2 + $i, $c2);
} else {
imagesetpixel($dstim, $srcX1 + $j, $srcY1 + $i, $gray);
// 去除第二个干扰水印
@ -220,13 +229,12 @@ class ImageVerify
return [
'point' => $srcX1,
'bgimg' => 'data:image/png;base64,' . base64_encode($bgimg),
'water' => 'data:image/png;base64,' . base64_encode($water)
'water' => 'data:image/png;base64,' . base64_encode($water),
];
}
/**
* 计算水印矩阵坐标
* @return void
* 计算水印矩阵坐标.
*/
private function withWaterPoint(): array
{
@ -241,10 +249,10 @@ class ImageVerify
// 第二个圆中心点
$c_2_x = $this->picHeight - $this->r;
$c_2_y = $lw + ($this->picHeight - ($lw) * 2) / 2;
$c_2_y = $lw + ($this->picHeight - $lw * 2) / 2;
for ($i = 0; $i < $this->picHeight; $i++) {
for ($j = 0; $j < $this->picWidth; $j++) {
for ($i = 0; $i < $this->picHeight; ++$i) {
for ($j = 0; $j < $this->picWidth; ++$j) {
// 根据公式x-a)² + (y-b)² = r² 算出像素是否在圆内
$d1 = pow($j - $c_1_x, 2) + pow($i - $c_1_y, 2);
$d2 = pow($j - $c_2_x, 2) + pow($i - $c_2_y, 2);
@ -258,4 +266,4 @@ class ImageVerify
return $waters;
}
}
}

View File

@ -1,35 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
use think\admin\Exception;
/**
* JsonRpc 客户端
* JsonRpc 客户端.
* @class JsonRpcClient
* @package think\admin\extend
*/
class JsonRpcClient
{
/**
* 请求ID
* @var integer
* 请求ID.
* @var int
*/
private $id;
@ -40,15 +41,13 @@ class JsonRpcClient
private $proxy;
/**
* 请求头部参数
* 请求头部参数.
* @var string
*/
private $header;
/**
* JsonRpcClient constructor.
* @param string $proxy
* @param array $header
*/
public function __construct(string $proxy, array $header = [])
{
@ -59,21 +58,19 @@ class JsonRpcClient
/**
* 执行 JsonRpc 请求
* @param string $method
* @param array $params
* @return mixed
* @throws \think\admin\Exception
* @throws Exception
*/
public function __call(string $method, array $params = [])
{
$options = [
'ssl' => [
'verify_peer' => false,
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
'http' => [
'method' => 'POST', "timeout" => 60,
'header' => join("\r\n", array_merge(['Content-Type:application/json'], $this->header, ['User-Agent:think-admin-jsonrpc', ''])),
'method' => 'POST', 'timeout' => 60,
'header' => join("\r\n", array_merge(['Content-Type:application/json'], $this->header, ['User-Agent:think-admin-jsonrpc', ''])),
'content' => json_encode(['jsonrpc' => '2.0', 'method' => $method, 'params' => $params, 'id' => $this->id], JSON_UNESCAPED_UNICODE),
],
];
@ -81,10 +78,12 @@ class JsonRpcClient
// Performs the HTTP POST
if ($fp = fopen($this->proxy, 'r', false, stream_context_create($options))) {
$response = '';
while ($line = fgets($fp)) $response .= trim($line) . "\n";
while ($line = fgets($fp)) {
$response .= trim($line) . "\n";
}
[, $response] = [fclose($fp), json_decode($response, true)];
} else {
throw new Exception(lang("Unable connect: %s", [$this->proxy]));
throw new Exception(lang('Unable connect: %s', [$this->proxy]));
}
} catch (Exception $exception) {
throw $exception;
@ -92,14 +91,16 @@ class JsonRpcClient
throw new Exception($exception->getMessage());
}
// Compatible with normal
if (isset($response['code']) && isset($response['info'])) {
if (isset($response['code'], $response['info'])) {
throw new Exception($response['info'], intval($response['code']), $response['data'] ?? []);
}
// Final checks and return
if (empty($response['id']) || $response['id'] != $this->id) {
throw new Exception(lang("Error flag ( Request tag: %s, Response tag: %s )", [$this->id, $response['id'] ?? '-']), 0, $response);
throw new Exception(lang('Error flag ( Request tag: %s, Response tag: %s )', [$this->id, $response['id'] ?? '-']), 0, $response);
}
if (is_null($response['error'])) {
return $response['result'];
}
if (is_null($response['error'])) return $response['result'];
throw new Exception($response['error']['message'], intval($response['error']['code']), $response['result'] ?? []);
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
@ -23,9 +25,8 @@ use think\Container;
use think\exception\HttpResponseException;
/**
* JsonRpc 服务端
* JsonRpc 服务端.
* @class JsonRpcServer
* @package think\admin\extend
*/
class JsonRpcServer
{
@ -37,7 +38,6 @@ class JsonRpcServer
/**
* JsonRpcServer constructor.
* @param App $app
*/
public function __construct(App $app)
{
@ -72,25 +72,28 @@ class JsonRpcServer
} elseif (!isset($request['id']) || !isset($request['method']) || !isset($request['params'])) {
$error = ['code' => '-32600', 'message' => lang('Invalid request.'), 'meaning' => lang('Invalid JSON parameter.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'] ?? '0', 'result' => null, 'error' => $error];
} else try {
if ($object instanceof \Exception) {
throw $object;
} elseif (strtolower($request['method']) === '_get_class_name_') {
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => get_class($object), 'error' => null];
} elseif (method_exists($object, $request['method'])) {
$result = call_user_func_array([$object, $request['method']], $request['params']);
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => $result, 'error' => null];
} else {
$info = lang('method not exists: %s::%s', [class_basename($object), $request['method']]);
$error = ['code' => '-32601', 'message' => $info, 'meaning' => lang('The method does not exist or is invalid.')];
} else {
try {
if ($object instanceof \Exception) {
throw $object;
}
if (strtolower($request['method']) === '_get_class_name_') {
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => get_class($object), 'error' => null];
} elseif (method_exists($object, $request['method'])) {
$result = call_user_func_array([$object, $request['method']], $request['params']);
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => $result, 'error' => null];
} else {
$info = lang('method not exists: %s::%s', [class_basename($object), $request['method']]);
$error = ['code' => '-32601', 'message' => $info, 'meaning' => lang('The method does not exist or is invalid.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => null, 'error' => $error];
}
} catch (\think\admin\Exception $exception) {
$error = ['code' => $exception->getCode(), 'message' => lang($exception->getMessage()), 'meaning' => lang('Business Exception.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => $exception->getData(), 'error' => $error];
} catch (\Exception $exception) {
$error = ['code' => $exception->getCode(), 'message' => lang($exception->getMessage()), 'meaning' => lang('System Exception.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => null, 'error' => $error];
}
} catch (\think\admin\Exception $exception) {
$error = ['code' => $exception->getCode(), 'message' => lang($exception->getMessage()), 'meaning' => lang('Business Exception.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => $exception->getData(), 'error' => $error];
} catch (\Exception $exception) {
$error = ['code' => $exception->getCode(), 'message' => lang($exception->getMessage()), 'meaning' => lang('System Exception.')];
$response = ['jsonrpc' => '2.0', 'id' => $request['id'], 'result' => null, 'error' => $error];
}
// Output the response
throw new HttpResponseException(json($response));
@ -98,7 +101,7 @@ class JsonRpcServer
}
/**
* 打印输出对象方法
* 打印输出对象方法.
* @param mixed $object
*/
protected function printMethod($object)
@ -107,11 +110,15 @@ class JsonRpcServer
$object = new \ReflectionClass($object);
echo "<h2>{$object->getName()}</h2><hr>";
foreach ($object->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if (stripos($method->getName(), '_') === 0) continue;
if (stripos($method->getName(), '_') === 0) {
continue;
}
$params = [];
foreach ($method->getParameters() as $parameter) {
$type = $parameter->getType();
if ($type instanceof \ReflectionType) $type = $type->getName();
if ($type instanceof \ReflectionType) {
$type = $type->getName();
}
$params[] = ($type ? "{$type} $" : '$') . $parameter->getName();
}
$params = count($params) > 0 ? join(', ', $params) : '';
@ -122,4 +129,4 @@ class JsonRpcServer
echo "<h3>[{$exception->getCode()}] {$exception->getMessage()}</h3>";
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
@ -23,9 +25,8 @@ use think\admin\Exception;
use think\admin\Library;
/**
* 接口 JWT 接口扩展
* 接口 JWT 接口扩展.
* @class JwtExtend
* @package think\admin\extend
* @method static bool isRejwt() 是否输出令牌
* @method static array getInData() 获取输入数据
*/
@ -38,58 +39,84 @@ class JwtExtend
private const signTypes = [
'HS256' => 'sha256',
'HS384' => 'sha384',
'HS512' => 'sha512'
'HS512' => 'sha512',
];
/**
* 是否返回令牌
* @var boolean
*/
private static $rejwt = false;
/**
* 当前请求数据
* @var array
*/
private static $input = [];
/**
* 获取原会话标签
* 获取原会话标签.
* @var string
*/
public static $sessionId = '';
/**
* 生成 jwt token
* 是否返回令牌.
* @var bool
*/
private static $rejwt = false;
/**
* 当前请求数据.
* @var array
*/
private static $input = [];
/**
* 兼容历史方法.
* @return array|string
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
switch ($method) {
case 'isRejwt': // 是否返回令牌
return self::$rejwt;
case 'getInData': // 获取请求数据
return self::$input;
case 'getToken': // 生成接口令牌
return self::token(...$arguments);
case 'verifyToken': // 验证接口令牌
return self::verify(...$arguments);
default:
throw new Exception("method not exists: JwtExtend::{$method}()");
}
}
/**
* 生成 jwt token.
* @param array $data jwt 载荷 格式如下非必须
* {
* "iss": "http://example.org", // 签发者IssuerJWT的签发者
* "sub": "1234567890", // 主题SubjectJWT所面向的用户
* "aud": "http://example.com", // 受众Audience接收JWT的一方
* "exp": 1625174400, // 过期时间Expiration timeJWT的过期时间戳
* "iat": 1625138400, // 签发时间Issued atJWT的签发时间戳
* "nbf": 1625138400, // 生效时间Not BeforeJWT的生效时间戳
* "...": ... // 其他扩展内容
* }
* {
* "iss": "http://example.org", // 签发者IssuerJWT的签发者
* "sub": "1234567890", // 主题SubjectJWT所面向的用户
* "aud": "http://example.com", // 受众Audience接收JWT的一方
* "exp": 1625174400, // 过期时间Expiration timeJWT的过期时间戳
* "iat": 1625138400, // 签发时间Issued atJWT的签发时间戳
* "nbf": 1625138400, // 生效时间Not BeforeJWT的生效时间戳
* "...": ... // 其他扩展内容
* }
* @param ?string $jwtkey 签名密钥
* @param ?boolean $rejwt 输出令牌
* @return string
* @param ?bool $rejwt 输出令牌
*/
public static function token(array $data = [], ?string $jwtkey = null, ?bool $rejwt = null): string
{
$jwtkey = self::jwtkey($jwtkey);
if (is_bool($rejwt)) self::$rejwt = $rejwt;
if (is_bool($rejwt)) {
self::$rejwt = $rejwt;
}
// JWT 载荷数据组装
[$fields, $payload] = [['iss', 'sub', 'aud', 'exp', 'iat', 'nbf'], ['iat' => time()]];
foreach ($data as $k => $v) if (in_array($k, $fields)) {
$payload[$k] = $v;
unset($data[$k]);
foreach ($data as $k => $v) {
if (in_array($k, $fields)) {
$payload[$k] = $v;
unset($data[$k]);
}
}
// 自定义需要的数据
$data['.ssid'] = self::withSess();
if (empty($data['.ssid'])) unset($data['.ssid']);
if (empty($data['.ssid'])) {
unset($data['.ssid']);
}
$payload['enc'] = CodeExtend::encrypt(json_encode($data, JSON_UNESCAPED_UNICODE), $jwtkey);
// 组装 JWT 内容格式
@ -99,22 +126,25 @@ class JwtExtend
}
/**
* 验证 token 是否有效, 默认验证 exp,nbf,iat 时间
* 验证 token 是否有效, 默认验证 exp,nbf,iat 时间.
* @param string $token 加密数据
* @param ?string $jwtkey 签名密钥
* @return array
* @throws \think\admin\Exception
* @throws Exception
*/
public static function verify(string $token, ?string $jwtkey = null): array
{
$tokens = explode('.', $token);
if (count($tokens) != 3) throw new Exception('数据解密失败!', 0, []);
if (count($tokens) != 3) {
throw new Exception('数据解密失败!', 0, []);
}
[$base64header, $base64payload, $signature] = $tokens;
// 加密算法
$header = json_decode(CodeExtend::deSafe64($base64header), true);
if (empty($header['alg'])) throw new Exception('数据解密失败!', 0, []);
if (empty($header['alg'])) {
throw new Exception('数据解密失败!', 0, []);
}
// 签名验证
$jwtkey = self::jwtkey($jwtkey);
@ -143,7 +173,9 @@ class JwtExtend
// 返回自定义数据字段
if (isset($payload['enc'])) {
$extra = json_decode(CodeExtend::decrypt($payload['enc'], $jwtkey), true);
if (!empty($extra['.ssid'])) self::$sessionId = $extra['.ssid'];
if (!empty($extra['.ssid'])) {
self::$sessionId = $extra['.ssid'];
}
unset($payload['enc'], $extra['.ssid']);
}
@ -151,28 +183,31 @@ class JwtExtend
}
/**
* 获取 JWT 密钥
* @param ?string $jwtkey
* @return string
* 获取 JWT 密钥.
*/
public static function jwtkey(?string $jwtkey = null): string
{
try {
if (!empty($jwtkey)) return $jwtkey;
if (!empty($jwtkey)) {
return $jwtkey;
}
// 优先读取配置文件
$jwtkey = config('app.jwtkey');
if (!empty($jwtkey)) return $jwtkey;
if (!empty($jwtkey)) {
return $jwtkey;
}
// 再次读取数据配置
$jwtkey = sysconf('data.jwtkey|raw');
if (!empty($jwtkey)) return $jwtkey;
if (!empty($jwtkey)) {
return $jwtkey;
}
// 自动生成新的密钥
$jwtkey = md5(uniqid(strval(rand(1000, 9999)), true));
sysconf('data.jwtkey', $jwtkey);
return $jwtkey;
} catch (\Exception $exception) {
trace_file($exception);
return 'thinkadmin';
@ -180,65 +215,40 @@ class JwtExtend
}
/**
* 输出模板变量
* @param \think\admin\Controller $class
* @param array $vars
* @return void
* 输出模板变量.
*/
public static function fetch(Controller $class, array $vars = [])
{
$ignore = array_keys(get_class_vars(Controller::class));
foreach ($class as $name => $value) if (!in_array($name, $ignore)) {
if (is_array($value) || is_numeric($value) || is_string($value) || is_bool($value) || is_null($value)) {
$vars[$name] = $value;
foreach ($class as $name => $value) {
if (!in_array($name, $ignore)) {
if (is_array($value) || is_numeric($value) || is_string($value) || is_bool($value) || is_null($value)) {
$vars[$name] = $value;
}
}
}
$class->success('获取变量成功!', $vars);
}
/**
* 获取原会话标识
* @return string
* 获取原会话标识.
*/
private static function withSess(): string
{
if (!isset(Library::$sapp->session)) return self::$sessionId = '';
if (!isset(Library::$sapp->session)) {
return self::$sessionId = '';
}
return self::$sessionId = Library::$sapp->session->getId();
}
/**
* 生成数据签名
* 生成数据签名.
* @param string $input base64UrlEncode(header).".".base64UrlEncode(payload)
* @param string $alg 算法方式
* @param ?string $key 签名密钥
* @return string
*/
private static function withSign(string $input, string $alg = 'HS256', ?string $key = null): string
{
return CodeExtend::enSafe64(hash_hmac(self::signTypes[$alg], $input, self::jwtkey($key), true));
}
/**
* 兼容历史方法
* @param string $method
* @param array $arguments
* @return array|string
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
switch ($method) {
case 'isRejwt': // 是否返回令牌
return self::$rejwt;
case 'getInData': // 获取请求数据
return self::$input;
case 'getToken': // 生成接口令牌
return self::token(...$arguments);
case 'verifyToken': // 验证接口令牌
return self::verify(...$arguments);
default:
throw new Exception("method not exists: JwtExtend::{$method}()");
}
}
}
}

View File

@ -1,45 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
use Exception;
use Phinx\Db\Adapter\AdapterInterface;
use Phinx\Db\Adapter\MysqlAdapter;
use Phinx\Db\Table;
use SplFileInfo;
use think\admin\Library;
use think\admin\model\SystemMenu;
use think\admin\service\ProcessService;
use think\helper\Str;
/**
* 数据库迁移扩展
* 数据库迁移扩展.
* @class PhinxExtend
* @package think\admin\extend
*/
class PhinxExtend
{
/**
* 批量写入菜单
* 批量写入菜单.
* @param array $zdata 菜单数据
* @param mixed $exists 检测条件
* @return boolean
*/
public static function write2menu(array $zdata, $exists = []): bool
{
@ -48,16 +46,20 @@ class PhinxExtend
if (!empty($exists) && SystemMenu::mk()->where($exists)->findOrEmpty()->isExists()) {
return false;
}
} catch (Exception $exception) {
} catch (\Exception $exception) {
return false;
}
// 循环写入系统菜单数据
foreach ($zdata as $one) {
$pid1 = static::write1menu($one);
if (!empty($one['subs'])) foreach ($one['subs'] as $two) {
$pid2 = static::write1menu($two, $pid1);
if (!empty($two['subs'])) foreach ($two['subs'] as $thr) {
static::write1menu($thr, $pid2);
if (!empty($one['subs'])) {
foreach ($one['subs'] as $two) {
$pid2 = static::write1menu($two, $pid1);
if (!empty($two['subs'])) {
foreach ($two['subs'] as $thr) {
static::write1menu($thr, $pid2);
}
}
}
}
}
@ -65,39 +67,19 @@ class PhinxExtend
}
/**
* 单个写入菜单
* @param array $menu 菜单数据
* @param integer $ppid 上级菜单
* @return integer
*/
private static function write1menu(array $menu, int $ppid = 0): int
{
return (int)SystemMenu::mk()->insertGetId([
'pid' => $ppid,
'url' => empty($menu['url']) ? (empty($menu['node']) ? '#' : $menu['node']) : $menu['url'],
'sort' => $menu['sort'] ?? 0,
'icon' => $menu['icon'] ?? '',
'node' => empty($menu['node']) ? (empty($menu['url']) ? '' : $menu['url']) : $menu['node'],
'title' => $menu['name'] ?? ($menu['title'] ?? ''),
'params' => $menu['params'] ?? '',
'target' => $menu['target'] ?? '_self',
]);
}
/**
* 升级更新数据表
* @param \Phinx\Db\Table $table
* 升级更新数据表.
* @param array $fields 字段配置
* @param array $indexs 索引配置
* @param boolean $force 强制更新
* @return \Phinx\Db\Table
* @param bool $force 强制更新
*/
public static function upgrade(Table $table, array $fields, array $indexs = [], bool $force = false): Table
{
[$_exists, $_fields] = [[], array_column($fields, 0)];
if ($isExists = $table->exists()) {
// 数据表存在且不强制时退出操作
if (empty($force)) return $table;
if (empty($force)) {
return $table;
}
foreach ($table->getColumns() as $column) {
$_exists[] = $name = $column->getName();
if (!in_array($name, $_fields)) {
@ -127,6 +109,106 @@ class PhinxExtend
return $table;
}
/**
* 创建数据库安装脚本.
* @return string[]
* @throws \Exception
*/
public static function create2table(array $tables = [], string $class = 'InstallTable', bool $force = false): array
{
if (Library::$sapp->db->connect()->getConfig('type') !== 'mysql') {
throw new \Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
}
$br = "\r\n";
$content = static::_build2table($tables, true, $force);
$content = substr($content, strpos($content, "\n") + 1);
$content = '<?php' . "{$br}{$br}use think\\admin\\extend\\PhinxExtend;{$br}use think\\migration\\Migrator;{$br}{$br}@set_time_limit(0);{$br}@ini_set('memory_limit', -1);{$br}{$br}class {$class} extends Migrator{$br}{{$br}{$content}}{$br}";
return ['file' => static::nextFile($class), 'text' => $content];
}
/**
* 创建数据库备份脚本.
* @throws \Exception
*/
public static function create2backup(array $tables = [], string $class = 'InstallPackage', bool $progress = true): array
{
if (Library::$sapp->db->connect()->getConfig('type') !== 'mysql') {
throw new \Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
}
// 处理菜单数据
[$menuData, $menuList] = [[], SystemMenu::mk()->where(['status' => 1])->order('sort desc,id asc')->select()->toArray()];
foreach (DataExtend::arr2tree($menuList) as $sub1) {
$one = ['name' => $sub1['title'], 'icon' => $sub1['icon'], 'url' => $sub1['url'], 'node' => $sub1['node'], 'params' => $sub1['params'], 'subs' => []];
if (!empty($sub1['sub'])) {
foreach ($sub1['sub'] as $sub2) {
$two = ['name' => $sub2['title'], 'icon' => $sub2['icon'], 'url' => $sub2['url'], 'node' => $sub2['node'], 'params' => $sub2['params'], 'subs' => []];
if (!empty($sub2['sub'])) {
foreach ($sub2['sub'] as $sub3) {
$two['subs'][] = ['name' => $sub3['title'], 'url' => $sub3['url'], 'node' => $sub3['node'], 'icon' => $sub3['icon'], 'params' => $sub3['params']];
}
}
if (empty($two['subs'])) {
unset($two['subs']);
}
$one['subs'][] = $two;
}
}
if (empty($one['subs'])) {
unset($one['subs']);
}
$menuData[] = $one;
}
// 备份数据表
[$extra, $version] = [[], strstr($filename = static::nextFile($class), '_', true)];
if (count($tables) > 0) {
foreach ($tables as $table) {
if (($count = ($db = Library::$sapp->db->table($table))->count()) > 0) {
$dataFileName = "{$version}/{$table}.data";
$dataFilePath = syspath("database/migrations/{$dataFileName}");
is_dir($dataDirectory = dirname($dataFilePath)) || mkdir($dataDirectory, 0777, true);
$progress && ProcessService::message(" -- Starting write {$table}.data ..." . PHP_EOL);
[$used, $fp] = [0, fopen($dataFilePath, 'w+')];
foreach ($db->cursor() as $item) {
fwrite($fp, json_encode($item, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n");
if ($progress && ($number = sprintf('%.4f', (++$used / $count) * 100) . '%')) {
ProcessService::message(" -- -- write {$table}.data: {$used}/{$count} {$number}", 1);
}
}
fclose($fp);
$extra[$table] = $dataFileName;
$progress && ProcessService::message(" -- Finished write {$table}.data, Total {$used} rows.", 2);
}
}
}
// 生成迁移脚本
$template = file_get_contents(dirname(__DIR__) . '/service/bin/package.stub');
$dataJson = json_encode($extra, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$menuJson = json_encode($menuData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$replaces = ['__CLASS__' => $class, '__MENU_JSON__' => $menuJson, '__DATA_JSON__' => $dataJson];
return ['file' => $filename, 'text' => str_replace(array_keys($replaces), array_values($replaces), $template)];
}
/**
* 单个写入菜单.
* @param array $menu 菜单数据
* @param int $ppid 上级菜单
*/
private static function write1menu(array $menu, int $ppid = 0): int
{
return (int)SystemMenu::mk()->insertGetId([
'pid' => $ppid,
'url' => empty($menu['url']) ? (empty($menu['node']) ? '#' : $menu['node']) : $menu['url'],
'sort' => $menu['sort'] ?? 0,
'icon' => $menu['icon'] ?? '',
'node' => empty($menu['node']) ? (empty($menu['url']) ? '' : $menu['url']) : $menu['node'],
'title' => $menu['name'] ?? ($menu['title'] ?? ''),
'params' => $menu['params'] ?? '',
'target' => $menu['target'] ?? '_self',
]);
}
/**
* 生成索引名称.
*
@ -147,101 +229,19 @@ class PhinxExtend
return sprintf('idx_%s_%s_%s', substr(md5($table), -4), $getInitials($table), $name);
}
/**
* 创建数据库安装脚本
* @param array $tables
* @param string $class
* @param boolean $force
* @return string[]
* @throws \Exception
*/
public static function create2table(array $tables = [], string $class = 'InstallTable', bool $force = false): array
{
if (Library::$sapp->db->connect()->getConfig('type') !== 'mysql') {
throw new Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
}
$br = "\r\n";
$content = static::_build2table($tables, true, $force);
$content = substr($content, strpos($content, "\n") + 1);
$content = '<?php' . "{$br}{$br}use think\\admin\\extend\\PhinxExtend;{$br}use think\migration\Migrator;{$br}{$br}@set_time_limit(0);{$br}@ini_set('memory_limit', -1);{$br}{$br}class {$class} extends Migrator{$br}{{$br}{$content}}{$br}";
return ['file' => static::nextFile($class), 'text' => $content];
}
/**
* 创建数据库备份脚本
* @param array $tables
* @param string $class
* @param boolean $progress
* @return array
* @throws \Exception
*/
public static function create2backup(array $tables = [], string $class = 'InstallPackage', bool $progress = true): array
{
if (Library::$sapp->db->connect()->getConfig('type') !== 'mysql') {
throw new Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
}
// 处理菜单数据
[$menuData, $menuList] = [[], SystemMenu::mk()->where(['status' => 1])->order('sort desc,id asc')->select()->toArray()];
foreach (DataExtend::arr2tree($menuList) as $sub1) {
$one = ['name' => $sub1['title'], 'icon' => $sub1['icon'], 'url' => $sub1['url'], 'node' => $sub1['node'], 'params' => $sub1['params'], 'subs' => []];
if (!empty($sub1['sub'])) foreach ($sub1['sub'] as $sub2) {
$two = ['name' => $sub2['title'], 'icon' => $sub2['icon'], 'url' => $sub2['url'], 'node' => $sub2['node'], 'params' => $sub2['params'], 'subs' => []];
if (!empty($sub2['sub'])) foreach ($sub2['sub'] as $sub3) {
$two['subs'][] = ['name' => $sub3['title'], 'url' => $sub3['url'], 'node' => $sub3['node'], 'icon' => $sub3['icon'], 'params' => $sub3['params']];
}
if (empty($two['subs'])) unset($two['subs']);
$one['subs'][] = $two;
}
if (empty($one['subs'])) unset($one['subs']);
$menuData[] = $one;
}
// 备份数据表
[$extra, $version] = [[], strstr($filename = static::nextFile($class), '_', true)];
if (count($tables) > 0) foreach ($tables as $table) {
if (($count = ($db = Library::$sapp->db->table($table))->count()) > 0) {
$dataFileName = "{$version}/{$table}.data";
$dataFilePath = syspath("database/migrations/{$dataFileName}");
is_dir($dataDirectory = dirname($dataFilePath)) || mkdir($dataDirectory, 0777, true);
$progress && ProcessService::message(" -- Starting write {$table}.data ..." . PHP_EOL);
[$used, $fp] = [0, fopen($dataFilePath, 'w+')];
foreach ($db->cursor() as $item) {
fwrite($fp, json_encode($item, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n");
if ($progress && ($number = sprintf("%.4f", (++$used / $count) * 100) . '%')) {
ProcessService::message(" -- -- write {$table}.data: {$used}/{$count} {$number}", 1);
}
}
fclose($fp);
$extra[$table] = $dataFileName;
$progress && ProcessService::message(" -- Finished write {$table}.data, Total {$used} rows.", 2);
}
}
// 生成迁移脚本
$template = file_get_contents(dirname(__DIR__) . '/service/bin/package.stub');
$dataJson = json_encode($extra, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$menuJson = json_encode($menuData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$replaces = ['__CLASS__' => $class, '__MENU_JSON__' => $menuJson, '__DATA_JSON__' => $dataJson];
return ['file' => $filename, 'text' => str_replace(array_keys($replaces), array_values($replaces), $template)];
}
/**
* 数组转代码
* @param array $data
* @return string
*/
private static function _arr2str(array $data): string
{
return preg_replace(['#\s+#', '#, \)$#', '#^array \( #'], [' ', ']', '[',], var_export($data, true));
return preg_replace(['#\s+#', '#, \)$#', '#^array \( #'], [' ', ']', '['], var_export($data, true));
}
/**
* 生成数据库表格创建模板
* @param array $tables 指定数据表
* @param boolean $rehtml 是否返回内容
* @param boolean $force 强制更新结构
* @return string
* @param bool $rehtml 是否返回内容
* @param bool $force 强制更新结构
* @throws \Exception
*/
private static function _build2table(array $tables = [], bool $rehtml = false, bool $force = false): string
@ -249,11 +249,13 @@ class PhinxExtend
$br = "\r\n";
$connect = Library::$sapp->db->connect();
if ($connect->getConfig('type') !== 'mysql') {
throw new Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
throw new \Exception(' ** Notify: 只支持 MySql 数据库生成数据库脚本');
}
$schema = $connect->getConfig('database');
$content = '<?php' . "{$br}{$br}\t/**{$br}\t * 创建数据库{$br}\t */{$br}\tpublic function change()\n\t{";
foreach ($tables as $table) $content .= "{$br}\t\t\$this->_create_{$table}();";
foreach ($tables as $table) {
$content .= "{$br}\t\t\$this->_create_{$table}();";
}
$content .= "{$br}\t}{$br}{$br}";
// 字段默认长度
@ -262,27 +264,26 @@ class PhinxExtend
// 字段类型转换 ( 仅需定义与MySQL不同的配置 )
$types = [
// 整形数字
'tinyint' => AdapterInterface::PHINX_TYPE_TINY_INTEGER,
'smallint' => AdapterInterface::PHINX_TYPE_SMALL_INTEGER,
'int' => AdapterInterface::PHINX_TYPE_INTEGER,
'bigint' => AdapterInterface::PHINX_TYPE_BIG_INTEGER,
'tinyint' => AdapterInterface::PHINX_TYPE_TINY_INTEGER,
'smallint' => AdapterInterface::PHINX_TYPE_SMALL_INTEGER,
'int' => AdapterInterface::PHINX_TYPE_INTEGER,
'bigint' => AdapterInterface::PHINX_TYPE_BIG_INTEGER,
// 字符类型
'varchar' => AdapterInterface::PHINX_TYPE_STRING,
'tinytext' => AdapterInterface::PHINX_TYPE_TEXT,
'varchar' => AdapterInterface::PHINX_TYPE_STRING,
'tinytext' => AdapterInterface::PHINX_TYPE_TEXT,
'mediumtext' => AdapterInterface::PHINX_TYPE_TEXT,
'longtext' => AdapterInterface::PHINX_TYPE_TEXT,
'longtext' => AdapterInterface::PHINX_TYPE_TEXT,
// 仅 mysql 有的字段需要单独处理
'set' => AdapterInterface::PHINX_TYPE_STRING,
'enum' => AdapterInterface::PHINX_TYPE_STRING,
'year' => AdapterInterface::PHINX_TYPE_INTEGER,
'mediumint' => AdapterInterface::PHINX_TYPE_INTEGER,
'tinyblob' => AdapterInterface::PHINX_TYPE_BLOB,
'longblob' => AdapterInterface::PHINX_TYPE_BLOB,
'set' => AdapterInterface::PHINX_TYPE_STRING,
'enum' => AdapterInterface::PHINX_TYPE_STRING,
'year' => AdapterInterface::PHINX_TYPE_INTEGER,
'mediumint' => AdapterInterface::PHINX_TYPE_INTEGER,
'tinyblob' => AdapterInterface::PHINX_TYPE_BLOB,
'longblob' => AdapterInterface::PHINX_TYPE_BLOB,
'mediumblob' => AdapterInterface::PHINX_TYPE_BLOB,
];
foreach ($tables as $table) {
// 读取数据表 - 备注参数
$comment = Library::$sapp->db->table('information_schema.TABLES')->where([
'TABLE_SCHEMA' => $schema, 'TABLE_NAME' => $table,
@ -310,7 +311,9 @@ CODE;
// 生成字段内容
$_fieldString = '[' . PHP_EOL;
foreach (Library::$sapp->db->getFields($table) as $field) {
if ($field['name'] === 'id') continue;
if ($field['name'] === 'id') {
continue;
}
$type = $types[$field['type']] ?? $field['type'];
$data = ['default' => $field['default'], 'null' => empty($field['notnull']), 'comment' => $field['comment'] ?? ''];
if ($field['type'] === 'longtext') {
@ -334,7 +337,7 @@ CODE;
$type = $types[$attr[1]] ?? 'decimal';
$data = array_merge(['precision' => intval($attr[2]), 'scale' => intval($attr[3])], $data);
}
$_fieldString .= "\t\t\t['{$field['name']}', '{$type}', " . self::_arr2str($data) . "]," . PHP_EOL;
$_fieldString .= "\t\t\t['{$field['name']}', '{$type}', " . self::_arr2str($data) . '],' . PHP_EOL;
}
$_fieldString .= "\t\t]";
// 生成索引内容
@ -356,14 +359,13 @@ CODE;
}
/**
* 生成下一个脚本名称
* 生成下一个脚本名称.
* @param string $class 脚本类名
* @return string
*/
private static function nextFile(string $class): string
{
[$snake, $items] = [Str::snake($class), [20010000000000]];
ToolsExtend::find(syspath('database/migrations'), 1, function (SplFileInfo $info) use ($snake, &$items) {
ToolsExtend::find(syspath('database/migrations'), 1, function (\SplFileInfo $info) use ($snake, &$items) {
if ($info->isFile()) {
$bname = pathinfo($info->getBasename(), PATHINFO_FILENAME);
$items[] = $version = intval(substr($bname, 0, 14));
@ -378,4 +380,4 @@ CODE;
// 计算下一个版本号
return sprintf("%s_{$snake}.php", min($items) - 1);
}
}
}

View File

@ -1,90 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
use Closure;
use FilesystemIterator;
use Generator;
use SplFileInfo;
use think\admin\Exception;
/**
* 通用工具扩展
* 通用工具扩展.
* @class ToolsExtend
* @package think\admin\extend
*/
class ToolsExtend
{
/**
* 兼容旧方式调用.
* @return array|bool
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
$methods = [
'copyfile' => 'copy',
'scandirectory' => 'scan',
'findfilesarray' => 'find',
'removeemptydirectory' => 'remove',
];
if ($real = $methods[strtolower($method)] ?? null) {
return self::{$real}(...$arguments);
}
throw new Exception("method not exists: ToolsExtend::{$method}()");
}
/**
* 扫描目录下的文件列表
* 扫描目录下的文件列表.
* @param string $path 扫描目录
* @param ?integer $depth 扫描深度
* @param ?int $depth 扫描深度
* @param string $ext 筛选后缀
* @param boolean $short 相对路径
* @return array
* @param bool $short 相对路径
*/
public static function scan(string $path, ?int $depth = null, string $ext = '', bool $short = true): array
{
return static::find($path, $depth, function (SplFileInfo $info) use ($ext) {
return static::find($path, $depth, function (\SplFileInfo $info) use ($ext) {
return $info->isDir() || $ext === '' || strtolower($info->getExtension()) === strtolower($ext);
}, $short);
}
/**
* 扫描目录并返回文件路径数组
* 扫描目录并返回文件路径数组.
* @param string $path 扫描目录
* @param ?integer $depth 扫描深度
* @param ?Closure $filter 文件过滤,返回 false 表示放弃
* @param boolean $short 是否返回相对于给定路径的短路径
* @param ?int $depth 扫描深度
* @param ?\Closure $filter 文件过滤,返回 false 表示放弃
* @param bool $short 是否返回相对于给定路径的短路径
* @return array 包含文件路径的数组
*/
public static function find(string $path, ?int $depth = null, ?Closure $filter = null, bool $short = true): array
public static function find(string $path, ?int $depth = null, ?\Closure $filter = null, bool $short = true): array
{
[$info, $files] = [new SplFileInfo($path), []];
[$info, $files] = [new \SplFileInfo($path), []];
if ($info->isDir() || $info->isFile()) {
if ($info->isFile() && ($filter === null || $filter($info) !== false)) {
$files[] = $short ? $info->getBasename() : $info->getPathname();
}
if ($info->isDir()) foreach (static::findFilesYield($info->getPathname(), $depth, $filter) as $file) {
$files[] = $short ? substr($file->getPathname(), strlen($info->getPathname()) + 1) : $file->getPathname();
if ($info->isDir()) {
foreach (static::findFilesYield($info->getPathname(), $depth, $filter) as $file) {
$files[] = $short ? substr($file->getPathname(), strlen($info->getPathname()) + 1) : $file->getPathname();
}
}
}
return $files;
}
/**
* 深度拷贝到指定目录
* 深度拷贝到指定目录.
* @param string $frdir 来源目录
* @param string $todir 目标目录
* @param array $files 指定文件
* @param boolean $force 强制替换
* @param boolean $remove 删除文件
* @return boolean
* @param bool $force 强制替换
* @param bool $remove 删除文件
*/
public static function copy(string $frdir, string $todir, array $files = [], bool $force = true, bool $remove = true): bool
{
$frdir = rtrim($frdir, '\\/') . DIRECTORY_SEPARATOR;
$todir = rtrim($todir, '\\/') . DIRECTORY_SEPARATOR;
$frdir = rtrim($frdir, '\/') . DIRECTORY_SEPARATOR;
$todir = rtrim($todir, '\/') . DIRECTORY_SEPARATOR;
// 扫描目录文件
if (empty($files) && is_dir($frdir)) {
$files = static::find($frdir, null, function (SplFileInfo $info) {
$files = static::find($frdir, null, function (\SplFileInfo $info) {
return $info->getBasename()[0] !== '.';
});
}
@ -104,61 +120,45 @@ class ToolsExtend
}
/**
* 移除清空目录
* @param string $path
* @return boolean
* 移除清空目录.
*/
public static function remove(string $path): bool
{
if (!file_exists($path)) return true;
if (is_file($path)) return unlink($path);
if (!file_exists($path)) {
return true;
}
if (is_file($path)) {
return unlink($path);
}
$dirs = [$path];
iterator_to_array(self::findFilesYield($path, null, function (SplFileInfo $file) use (&$dirs) {
iterator_to_array(self::findFilesYield($path, null, function (\SplFileInfo $file) use (&$dirs) {
$file->isDir() ? $dirs[] = $file->getPathname() : unlink($file->getPathname());
}));
usort($dirs, function ($a, $b) {
return strlen($b) <=> strlen($a);
});
foreach ($dirs as $dir) file_exists($dir) && is_dir($dir) && rmdir($dir);
foreach ($dirs as $dir) {
file_exists($dir) && is_dir($dir) && rmdir($dir);
}
return !file_exists($path);
}
/**
* 兼容旧方式调用
* @param string $method
* @param array $arguments
* @return array|bool
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
$methods = [
'copyfile' => 'copy',
'scandirectory' => 'scan',
'findfilesarray' => 'find',
'removeemptydirectory' => 'remove',
];
if ($real = $methods[strtolower($method)] ?? null) {
return self::{$real}(...$arguments);
} else {
throw new Exception("method not exists: ToolsExtend::{$method}()");
}
}
/**
* 递归扫描指定目录,返回文件或目录的 SplFileInfo 对象。
* @param string $path 目录路径
* @param ?integer $depth 扫描深度
* @param \Closure|null $filter 文件过滤,返回 false 表示放弃
* @param boolean $appendPath 是否包含目录本身在结果中
* @param integer $currDepth 当前深度,临时变量递归时使用
* @return \Generator 返回 SplFileInfo 对象的生成器
* @param string $path 目录路径
* @param ?int $depth 扫描深度
* @param null|\Closure $filter 文件过滤,返回 false 表示放弃
* @param bool $appendPath 是否包含目录本身在结果中
* @param int $currDepth 当前深度,临时变量递归时使用
* @return \Generator 返回 SplFileInfo 对象的生成器
*/
public static function findFilesYield(string $path, ?int $depth = null, ?Closure $filter = null, bool $appendPath = false, int $currDepth = 1): Generator
public static function findFilesYield(string $path, ?int $depth = null, ?\Closure $filter = null, bool $appendPath = false, int $currDepth = 1): \Generator
{
if (file_exists($path) && is_dir($path) && (is_null($depth) || $currDepth <= $depth)) {
foreach (new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS) as $item) {
if ($filter !== null && $filter($item) === false) continue;
foreach (new \FilesystemIterator($path, \FilesystemIterator::SKIP_DOTS) as $item) {
if ($filter !== null && $filter($item) === false) {
continue;
}
if ($item->isDir() && !$item->isLink()) {
$appendPath && yield $item;
yield from static::findFilesYield($item->getPathname(), $depth, $filter, $appendPath, $currDepth + 1);
@ -168,4 +168,4 @@ class ToolsExtend
}
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
@ -22,9 +24,8 @@ use think\admin\contract\StreamInterface;
use think\Model;
/**
* 虚拟模型构建协议
* 虚拟模型构建协议.
* @class VirtualModel
* @package think\admin\extend
*/
class VirtualModel extends \stdClass implements StreamInterface
{
@ -35,8 +36,8 @@ class VirtualModel extends \stdClass implements StreamInterface
private $template;
/**
* 读取进度标量
* @var integer
* 读取进度标量.
* @var int
*/
private $position;
@ -44,7 +45,9 @@ class VirtualModel extends \stdClass implements StreamInterface
{
// 解析链接参数
$attr = parse_url($path);
if (empty($attr['fragment'])) $attr['fragment'] = '';
if (empty($attr['fragment'])) {
$attr['fragment'] = '';
}
$type = strtolower($attr['fragment'] ?: 'default');
// 生成模型代码
@ -71,13 +74,9 @@ class VirtualModel extends \stdClass implements StreamInterface
return $this->position >= strlen($this->template);
}
public function stream_cast(int $cast_as)
{
}
public function stream_cast(int $cast_as) {}
public function stream_close(): void
{
}
public function stream_close(): void {}
public function stream_flush(): bool
{
@ -170,11 +169,10 @@ class VirtualModel extends \stdClass implements StreamInterface
}
/**
* 创建虚拟模型
* 创建虚拟模型.
* @param mixed $name 模型名称
* @param array $data 模型数据
* @param mixed $conn 默认链接
* @return \think\Model
*/
public static function mk(string $name, array $data = [], string $conn = ''): Model
{
@ -187,4 +185,4 @@ class VirtualModel extends \stdClass implements StreamInterface
}
return new $class($data);
}
}
}

View File

@ -1,41 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
use think\admin\Helper;
use think\db\BaseQuery;
use think\db\exception\DbException;
use think\Model;
/**
* 通用删除管理器
* 通用删除管理器.
* @class DeleteHelper
* @package think\admin\helper
*/
class DeleteHelper extends Helper
{
/**
* 逻辑器初始化
* 逻辑器初始化.
* @param BaseQuery|Model|string $dbQuery
* @param string $field 操作数据主键
* @param mixed $where 额外更新条件
* @return boolean|void
* @throws \think\db\exception\DbException
* @return bool|void
* @throws DbException
*/
public function init($dbQuery, string $field = '', $where = [])
{
@ -44,13 +46,15 @@ class DeleteHelper extends Helper
$value = $this->app->request->post($field);
// 查询限制处理
if (!empty($where)) $query->where($where);
if (!empty($where)) {
$query->where($where);
}
if (!isset($where[$field]) && is_string($value)) {
$query->whereIn($field, str2arr($value));
}
// 前置回调处理
if (false === $this->class->callback('_delete_filter', $query, $where)) {
if ($this->class->callback('_delete_filter', $query, $where) === false) {
return false;
}
@ -63,11 +67,19 @@ class DeleteHelper extends Helper
$data = [];
if (method_exists($query, 'getTableFields')) {
$fields = $query->getTableFields();
if (in_array('deleted', $fields)) $data['deleted'] = 1;
if (in_array('is_deleted', $fields)) $data['is_deleted'] = 1;
if (in_array('deleted', $fields)) {
$data['deleted'] = 1;
}
if (in_array('is_deleted', $fields)) {
$data['is_deleted'] = 1;
}
if (isset($data['deleted']) || isset($data['is_deleted'])) {
if (in_array('deleted_at', $fields)) $data['deleted_at'] = date('Y-m-d H:i:s');
if (in_array('deleted_time', $fields)) $data['deleted_time'] = time();
if (in_array('deleted_at', $fields)) {
$data['deleted_at'] = date('Y-m-d H:i:s');
}
if (in_array('deleted_time', $fields)) {
$data['deleted_time'] = time();
}
}
}
@ -81,7 +93,7 @@ class DeleteHelper extends Helper
}
// 结果回调处理
if (false === $this->class->callback('_delete_result', $result)) {
if ($this->class->callback('_delete_result', $result) === false) {
return $result;
}

View File

@ -1,48 +1,52 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
use think\admin\Exception;
use think\admin\Helper;
use think\admin\service\SystemService;
use think\db\BaseQuery;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
/**
* 表单视图管理器
* 表单视图管理器.
* @class FormHelper
* @package think\admin\helper
*/
class FormHelper extends Helper
{
/**
* 逻辑器初始化
* 逻辑器初始化.
* @param BaseQuery|Model|string $dbQuery
* @param string $template 视图模板名称
* @param string $field 指定数据主键
* @param mixed $where 限定更新条件
* @param array $edata 表单扩展数据
* @return void|array|boolean
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array|bool|void
* @throws Exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function init($dbQuery, string $template = '', string $field = '', $where = [], array $edata = [])
{
@ -52,10 +56,12 @@ class FormHelper extends Helper
if ($this->app->request->isGet()) {
if ($value !== null) {
$exist = $query->where([$field => $value])->where($where)->find();
if ($exist instanceof Model) $exist = $exist->toArray();
if ($exist instanceof Model) {
$exist = $exist->toArray();
}
$edata = array_merge($edata, $exist ?: []);
}
if (false !== $this->class->callback('_form_filter', $edata)) {
if ($this->class->callback('_form_filter', $edata) !== false) {
$this->class->fetch($template, ['vo' => $edata]);
} else {
return $edata;
@ -63,9 +69,9 @@ class FormHelper extends Helper
}
if ($this->app->request->isPost()) {
$edata = array_merge($this->app->request->post(), $edata);
if (false !== $this->class->callback('_form_filter', $edata, $where)) {
if ($this->class->callback('_form_filter', $edata, $where) !== false) {
$result = SystemService::save($query, $edata, $field, $where) !== false;
if (false !== $this->class->callback('_form_result', $result, $edata)) {
if ($this->class->callback('_form_result', $result, $edata) !== false) {
if ($result !== false) {
$this->class->success('数据保存成功!');
} else {
@ -76,4 +82,4 @@ class FormHelper extends Helper
}
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
@ -22,29 +24,30 @@ use think\admin\Helper;
use think\admin\Library;
use think\admin\service\AdminService;
use think\db\BaseQuery;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;
use think\exception\HttpResponseException;
use think\Model;
/**
* 列表处理管理器
* 列表处理管理器.
* @class PageHelper
* @package think\admin\helper
*/
class PageHelper extends Helper
{
/**
* 逻辑器初始化
* 逻辑器初始化.
* @param BaseQuery|Model|string $dbQuery
* @param boolean|integer $page 是否分页或指定分页
* @param boolean $display 是否渲染模板
* @param boolean|integer $total 集合分页记录数
* @param integer $limit 集合每页记录数
* @param bool|int $page 是否分页或指定分页
* @param bool $display 是否渲染模板
* @param bool|int $total 集合分页记录数
* @param int $limit 集合每页记录数
* @param string $template 模板文件名称
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function init($dbQuery, $page = true, bool $display = true, $total = false, int $limit = 0, string $template = ''): array
{
@ -62,15 +65,19 @@ class PageHelper extends Helper
$prefix = $inner ? (sysuri('admin/index/index') . '#') : '';
// 生成分页数据
$config = ['list_rows' => $limit, 'query' => $get];
if (is_numeric($page)) $config['page'] = $page;
if (is_numeric($page)) {
$config['page'] = $page;
}
$data = ($paginate = $query->paginate($config, $this->getCount($query, $total)))->toArray();
$result = ['page' => ['limit' => $data['per_page'], 'total' => $data['total'], 'pages' => $data['last_page'], 'current' => $data['current_page']], 'list' => $data['data']];
// 分页跳转参数
$select = "<select onchange='location.href=this.options[this.selectedIndex].value'>";
if (in_array($limit, $limits)) foreach ($limits as $num) {
$get = array_merge($get, ['limit' => $num, 'page' => 1]);
$url = $this->app->request->baseUrl() . '?' . http_build_query($get, '', '&', PHP_QUERY_RFC3986);
$select .= sprintf('<option data-num="%d" value="%s" %s>%d</option>', $num, $prefix . $url, $limit === $num ? 'selected' : '', $num);
if (in_array($limit, $limits)) {
foreach ($limits as $num) {
$get = array_merge($get, ['limit' => $num, 'page' => 1]);
$url = $this->app->request->baseUrl() . '?' . http_build_query($get, '', '&', PHP_QUERY_RFC3986);
$select .= sprintf('<option data-num="%d" value="%s" %s>%d</option>', $num, $prefix . $url, $limit === $num ? 'selected' : '', $num);
}
} else {
$select .= "<option selected>{$limit}</option>";
}
@ -80,7 +87,7 @@ class PageHelper extends Helper
} else {
$result = ['list' => $query->select()->toArray()];
}
if (false !== $this->class->callback('_page_filter', $result['list'], $result) && $display) {
if ($this->class->callback('_page_filter', $result['list'], $result) !== false && $display) {
if ($this->output === 'get.json') {
$this->class->success('JSON-DATA', $result);
} else {
@ -91,13 +98,11 @@ class PageHelper extends Helper
}
/**
* 组件 Layui.Table 处理
* 组件 Layui.Table 处理.
* @param BaseQuery|Model|string $dbQuery
* @param string $template
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function layTable($dbQuery, string $template = ''): array
{
@ -105,7 +110,7 @@ class PageHelper extends Helper
$get = $this->app->request->get();
$query = static::buildQuery($dbQuery);
// 根据参数排序
if (isset($get['_field_']) && isset($get['_order_'])) {
if (isset($get['_field_'], $get['_order_'])) {
$dbQuery->order("{$get['_field_']} {$get['_order_']}");
}
return PageHelper::instance()->init($query);
@ -114,7 +119,7 @@ class PageHelper extends Helper
$get = $this->app->request->get();
$query = $this->autoSortQuery($dbQuery);
// 根据参数排序
if (isset($get['_field_']) && isset($get['_order_'])) {
if (isset($get['_field_'], $get['_order_'])) {
$query->order("{$get['_field_']} {$get['_order_']}");
}
// 数据分页处理
@ -126,54 +131,20 @@ class PageHelper extends Helper
$data = $query->paginate($cfg, static::getCount($query))->toArray();
$result = ['msg' => '', 'code' => 0, 'count' => $data['total'], 'data' => $data['data']];
}
if (false !== $this->class->callback('_page_filter', $result['data'], $result)) {
if ($this->class->callback('_page_filter', $result['data'], $result) !== false) {
static::xssFilter($result['data']);
throw new HttpResponseException(json($result));
} else {
return $result;
}
} else {
$this->class->fetch($template);
return [];
return $result;
}
}
/**
* 输出 XSS 过滤处理
* @param array $items
*/
private static function xssFilter(array &$items)
{
foreach ($items as &$item) if (is_array($item)) {
static::xssFilter($item);
} elseif (is_string($item)) {
$item = htmlspecialchars($item, ENT_QUOTES);
}
}
/**
* 查询对象数量统计
* @param BaseQuery|Query $query
* @param boolean|integer $total
* @return integer|boolean|string
* @throws \think\db\exception\DbException
*/
private static function getCount($query, $total = false)
{
if ($total === true || is_numeric($total)) return $total;
[$query, $options] = [clone $query, $query->getOptions()];
if (isset($options['order'])) $query->removeOption('order');
Library::$sapp->db->trigger('think_before_page_count', $query);
if (empty($options['union'])) return $query->count();
$table = [$query->buildSql() => '_union_count_'];
return $query->newQuery()->table($table)->count();
$this->class->fetch($template);
return [];
}
/**
* 绑定排序并返回操作对象
* @param BaseQuery|Model|string $dbQuery
* @param string $field 指定排序字段
* @return \think\db\Query
*/
public function autoSortQuery($dbQuery, string $field = 'sort'): Query
{
@ -196,4 +167,42 @@ class PageHelper extends Helper
}
return $query;
}
}
/**
* 输出 XSS 过滤处理.
*/
private static function xssFilter(array &$items)
{
foreach ($items as &$item) {
if (is_array($item)) {
static::xssFilter($item);
} elseif (is_string($item)) {
$item = htmlspecialchars($item, ENT_QUOTES);
}
}
}
/**
* 查询对象数量统计
* @param BaseQuery|Query $query
* @param bool|int $total
* @return bool|int|string
* @throws DbException
*/
private static function getCount($query, $total = false)
{
if ($total === true || is_numeric($total)) {
return $total;
}
[$query, $options] = [clone $query, $query->getOptions()];
if (isset($options['order'])) {
$query->removeOption('order');
}
Library::$sapp->db->trigger('think_before_page_count', $query);
if (empty($options['union'])) {
return $query->count();
}
$table = [$query->buildSql() => '_union_count_'];
return $query->newQuery()->table($table)->count();
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
@ -22,45 +24,73 @@ use think\admin\Helper;
use think\admin\service\SystemService;
use think\Container;
use think\db\BaseQuery;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;
use think\Model;
/**
* 搜索条件处理器
* @see \think\db\Query
* 搜索条件处理器.
* @see Query
* @mixin \think\db\Query
* @class QueryHelper
* @package think\admin\helper
*
* --- 动态方法调用声明
* @method bool mSave(array $data = [], string $field = '', mixed $where = []) 快捷更新
* @method bool mDelete(string $field = '', mixed $where = []) 快捷删除
* @method bool|array mForm(string $tpl = '', string $field = '', mixed $where = [], array $data = []) 快捷表单
* @method bool|integer mUpdate(array $data = [], string $field = '', mixed $where = []) 快捷保存
* @method array|bool mForm(string $tpl = '', string $field = '', mixed $where = [], array $data = []) 快捷表单
* @method bool|int mUpdate(array $data = [], string $field = '', mixed $where = []) 快捷保存
*/
class QueryHelper extends Helper
{
/**
* 分页助手工具
* 分页助手工具.
* @var PageHelper
*/
protected $page;
/**
* 当前数据操作
* 当前数据操作.
* @var Query
*/
protected $query;
/**
* 初始化默认数据
* 初始化默认数据.
* @var array
*/
protected $input;
/**
* 克隆属性复制.
*/
public function __clone()
{
$this->page = clone $this->page;
$this->query = clone $this->query;
}
/**
* QueryHelper call.
* @param string $name 调用方法名称
* @param array $args 调用参数内容
* @return $this|mixed
*/
public function __call(string $name, array $args)
{
return static::make($this->query, $name, $args, function ($name, $args) {
if (is_callable($callable = [$this->query, $name])) {
$value = call_user_func_array($callable, $args);
if ($name[0] === '_' || $value instanceof $this->query) {
return $this;
}
return $value;
}
return $this;
});
}
/**
* 获取当前Db操作对象
* @return Query
*/
public function db(): Query
{
@ -68,10 +98,10 @@ class QueryHelper extends Helper
}
/**
* 逻辑器初始化
* 逻辑器初始化.
* @param BaseQuery|Model|string $dbQuery
* @param string|array|null $input 输入数据
* @param callable|null $callable 初始回调
* @param null|array|string $input 输入数据
* @param null|callable $callable 初始回调
* @return $this
*/
public function init($dbQuery, $input = null, ?callable $callable = null): QueryHelper
@ -84,10 +114,10 @@ class QueryHelper extends Helper
}
/**
* 设置 Like 查询条件
* @param string|array $fields 查询字段
* 设置 Like 查询条件.
* @param array|string $fields 查询字段
* @param string $split 前后分割符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
@ -107,9 +137,9 @@ class QueryHelper extends Helper
}
/**
* 设置 Equal 查询条件
* @param string|array $fields 查询字段
* @param string|array|null $input 输入类型
* 设置 Equal 查询条件.
* @param array|string $fields 查询字段
* @param null|array|string $input 输入类型
* @param string $alias 别名分割符
* @return $this
*/
@ -129,10 +159,10 @@ class QueryHelper extends Helper
}
/**
* 设置 IN 区间查询
* @param string|array $fields 查询字段
* 设置 IN 区间查询.
* @param array|string $fields 查询字段
* @param string $split 输入分隔符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
@ -152,10 +182,10 @@ class QueryHelper extends Helper
}
/**
* 两字段范围查询
* 两字段范围查询.
* @example field1:field2#field,field11:field22#field00
* @param string|array $fields 查询字段
* @param string|array|null $input 输入数据
* @param array|string $fields 查询字段
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
@ -179,10 +209,10 @@ class QueryHelper extends Helper
}
/**
* 设置内容区间查询
* @param string|array $fields 查询字段
* 设置内容区间查询.
* @param array|string $fields 查询字段
* @param string $split 输入分隔符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
@ -192,48 +222,51 @@ class QueryHelper extends Helper
}
/**
* 设置日期时间区间查询
* @param string|array $fields 查询字段
* 设置日期时间区间查询.
* @param array|string $fields 查询字段
* @param string $split 输入分隔符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
public function dateBetween($fields, string $split = ' - ', $input = null, string $alias = '#'): QueryHelper
{
return $this->setBetweenWhere($fields, $split, $input, $alias, static function ($value, $type) {
if (preg_match('#^\d{4}(-\d\d){2}\s+\d\d(:\d\d){2}$#', $value)) return $value;
if (preg_match('#^\d{4}(-\d\d){2}\s+\d\d(:\d\d){2}$#', $value)) {
return $value;
}
return $type === 'after' ? "{$value} 23:59:59" : "{$value} 00:00:00";
});
}
/**
* 设置时间戳区间查询
* @param string|array $fields 查询字段
* 设置时间戳区间查询.
* @param array|string $fields 查询字段
* @param string $split 输入分隔符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @return $this
*/
public function timeBetween($fields, string $split = ' - ', $input = null, string $alias = '#'): QueryHelper
{
return $this->setBetweenWhere($fields, $split, $input, $alias, static function ($value, $type) {
if (preg_match('#^\d{4}(-\d\d){2}\s+\d\d(:\d\d){2}$#', $value)) return strtotime($value);
if (preg_match('#^\d{4}(-\d\d){2}\s+\d\d(:\d\d){2}$#', $value)) {
return strtotime($value);
}
return $type === 'after' ? strtotime("{$value} 23:59:59") : strtotime("{$value} 00:00:00");
});
}
/**
* 实例化分页管理器
* @param boolean|integer $page 是否启用分页
* @param boolean $display 是否渲染模板
* @param boolean|integer $total 集合分页记录数
* @param integer $limit 集合每页记录数
* 实例化分页管理器.
* @param bool|int $page 是否启用分页
* @param bool $display 是否渲染模板
* @param bool|int $total 集合分页记录数
* @param int $limit 集合每页记录数
* @param string $template 模板文件名称
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function page($page = true, bool $display = true, $total = false, int $limit = 0, string $template = ''): array
{
@ -241,7 +274,7 @@ class QueryHelper extends Helper
}
/**
* 清空数据并保留表结构
* 清空数据并保留表结构.
* @return $this
*/
public function empty(): QueryHelper
@ -252,17 +285,18 @@ class QueryHelper extends Helper
$this->query->getConnection()->execute("truncate table `{$table}`");
} elseif (in_array($ctype, ['sqlsrv', 'oracle', 'pgsql'])) {
$this->query->getConnection()->execute("truncate table {$table}");
} else try {
$this->query->newQuery()->whereRaw('1=1')->delete();
} catch (\Throwable $exception) {
trace_file($exception);
} else {
try {
$this->query->newQuery()->whereRaw('1=1')->delete();
} catch (\Throwable $exception) {
trace_file($exception);
}
}
return $this;
}
/**
* 中间回调处理
* @param callable $after
* 中间回调处理.
* @return $this
*/
public function filter(callable $after): QueryHelper
@ -272,13 +306,13 @@ class QueryHelper extends Helper
}
/**
* Layui.Table 组件数据
* Layui.Table 组件数据.
* @param ?callable $befor 表单前置操作
* @param ?callable $after 表单后置操作
* @param string $template 视图模板文件
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function layTable(?callable $befor = null, ?callable $after = null, string $template = '')
{
@ -296,12 +330,33 @@ class QueryHelper extends Helper
}
/**
* 设置区域查询条件
* @param string|array $fields 查询字段
* 快捷助手调用勾子.
* @param Model|Query|string $model
* @return false|int|mixed|QueryHelper
*/
public static function make($model, string $method = 'init', array $args = [], ?callable $nohook = null)
{
$hooks = [
'mForm' => [FormHelper::class, 'init'],
'mSave' => [SaveHelper::class, 'init'],
'mQuery' => [QueryHelper::class, 'init'],
'mDelete' => [DeleteHelper::class, 'init'],
'mUpdate' => [SystemService::class, 'update'],
];
if (isset($hooks[$method])) {
[$class, $method] = $hooks[$method];
return Container::getInstance()->invokeClass($class)->{$method}($model, ...$args);
}
return is_callable($nohook) ? $nohook($method, $args) : false;
}
/**
* 设置区域查询条件.
* @param array|string $fields 查询字段
* @param string $split 输入分隔符
* @param string|array|null $input 输入数据
* @param null|array|string $input 输入数据
* @param string $alias 别名分割符
* @param callable|null $callback 回调函数
* @param null|callable $callback 回调函数
* @return $this
*/
private function setBetweenWhere($fields, string $split = ' ', $input = null, string $alias = '#', ?callable $callback = null): QueryHelper
@ -325,74 +380,15 @@ class QueryHelper extends Helper
}
/**
* 获取输入数据
* @param string|array|null $input
* @return array
* 获取输入数据.
* @param null|array|string $input
*/
private function getInputData($input): array
{
if (is_array($input)) {
return $input;
} else {
$input = $input ?: 'request';
return $this->app->request->$input();
}
}
/**
* 克隆属性复制
* @return void
*/
public function __clone()
{
$this->page = clone $this->page;
$this->query = clone $this->query;
}
/**
* QueryHelper call.
* @param string $name 调用方法名称
* @param array $args 调用参数内容
* @return $this|mixed
*/
public function __call(string $name, array $args)
{
return static::make($this->query, $name, $args, function ($name, $args) {
if (is_callable($callable = [$this->query, $name])) {
$value = call_user_func_array($callable, $args);
if ($name[0] === '_' || $value instanceof $this->query) {
return $this;
} else {
return $value;
}
} else {
return $this;
}
});
}
/**
* 快捷助手调用勾子
* @param string|Model|Query $model
* @param string $method
* @param array $args
* @param callable|null $nohook
* @return mixed|false|integer|QueryHelper
*/
public static function make($model, string $method = 'init', array $args = [], ?callable $nohook = null)
{
$hooks = [
'mForm' => [FormHelper::class, 'init'],
'mSave' => [SaveHelper::class, 'init'],
'mQuery' => [QueryHelper::class, 'init'],
'mDelete' => [DeleteHelper::class, 'init'],
'mUpdate' => [SystemService::class, 'update'],
];
if (isset($hooks[$method])) {
[$class, $method] = $hooks[$method];
return Container::getInstance()->invokeClass($class)->$method($model, ...$args);
} else {
return is_callable($nohook) ? $nohook($method, $args) : false;
}
$input = $input ?: 'request';
return $this->app->request->{$input}();
}
}

View File

@ -1,43 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
use think\admin\Helper;
use think\db\BaseQuery;
use think\db\exception\DbException;
use think\Model;
/**
* 数据更新管理器
* 数据更新管理器.
* @class SaveHelper
* @package think\admin\helper
*/
class SaveHelper extends Helper
{
/**
* 逻辑器初始化
* 逻辑器初始化.
* @param BaseQuery|Model|string $dbQuery
* @param array $edata 表单扩展数据
* @param string $field 数据对象主键
* @param mixed $where 额外更新条件
* @return boolean|void
* @throws \think\db\exception\DbException
* @return bool|void
* @throws DbException
*/
public function init($dbQuery, array $edata = [], string $field = '', $where = [])
{
@ -49,11 +50,13 @@ class SaveHelper extends Helper
// 主键限制处理
if (!isset($where[$field]) && !is_null($value)) {
$query->whereIn($field, str2arr(strval($value)));
if (isset($edata)) unset($edata[$field]);
if (isset($edata)) {
unset($edata[$field]);
}
}
// 前置回调处理
if (false === $this->class->callback('_save_filter', $query, $edata)) {
if ($this->class->callback('_save_filter', $query, $edata) === false) {
return false;
}
@ -68,7 +71,7 @@ class SaveHelper extends Helper
// 结果回调处理
$result = true;
if (false === $this->class->callback('_save_result', $result, $model)) {
if ($this->class->callback('_save_result', $result, $model) === false) {
return $result;
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
@ -23,37 +25,42 @@ use think\admin\Library;
use think\exception\HttpResponseException;
/**
* 表单令牌验证器
* 表单令牌验证器.
* @class TokenHelper
* @package think\admin\helper
*/
class TokenHelper extends Helper
{
/**
* 初始化验证码器
* @param boolean $return
* @return boolean|void
* 初始化验证码器.
* @return bool|void
*/
public function init(bool $return = false)
{
$this->class->csrf_state = true;
if (!$this->app->request->isPost()) return true;
if (!$this->app->request->isPost()) {
return true;
}
$token = $this->app->request->post('_token_');
$extra = ['_token_' => $token ?: $this->app->request->header('User-Form-Token')];
if ($this->app->request->checkToken('_token_', $extra)) return true; elseif ($return) return false;
if ($this->app->request->checkToken('_token_', $extra)) {
return true;
}
if ($return) {
return false;
}
$this->class->error($this->class->csrf_message ?: '表单令牌验证失败!');
}
/**
* 返回视图内容
* 返回视图内容.
* @param string $tpl 模板名称
* @param array $vars 模板变量
* @param string|null $node 授权节点
* @param null|string $node 授权节点
*/
public static function fetch(string $tpl = '', array $vars = [], ?string $node = null)
{
throw new HttpResponseException(view($tpl, $vars, 200, static function ($html) use ($node) {
return preg_replace_callback('/<\/form>/i', static function () use ($node) {
throw new HttpResponseException(view($tpl, $vars, 200, static function ($html) {
return preg_replace_callback('/<\/form>/i', static function () {
return sprintf("<input type='hidden' name='_token_' value='%s'></form>", static::token());
}, $html);
}));
@ -61,11 +68,10 @@ class TokenHelper extends Helper
/**
* 返回表单令牌数据
* 为了兼容JWT模式使用表单令牌
* @return string
* 为了兼容JWT模式使用表单令牌.
*/
public static function token(): string
{
return Library::$sapp->request->buildToken('_token_');
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\helper;
@ -22,17 +24,16 @@ use think\admin\Helper;
use think\Validate;
/**
* 快捷输入验证器
* 快捷输入验证器.
* @class ValidateHelper
* @package think\admin\helper
*/
class ValidateHelper extends Helper
{
/**
* 快捷输入并验证( 支持 规则 # 别名
* 快捷输入并验证( 支持 规则 # 别名 .
* @param array $rules 验证规则( 验证信息数组
* @param string|array $input 输入内容 ( post. get. )
* @param callable|null $callable 异常处理操作
* @param array|string $input 输入内容 ( post. get. )
* @param null|callable $callable 异常处理操作
* @return array|void
*
* age.require => message // 最大值限定
@ -47,7 +48,7 @@ class ValidateHelper extends Helper
{
if (is_string($input)) {
$type = trim($input, '.') ?: 'param';
$input = $this->app->request->$type();
$input = $this->app->request->{$type}();
}
[$data, $rule, $info] = [[], [], []];
foreach ($rules as $key => $value) {
@ -59,8 +60,12 @@ class ValidateHelper extends Helper
} elseif (preg_match('|^(.*?)\.(.*?)#(.*?)#?$|', "{$key}#", $matches)) {
[, $_key, $_rule, $alias] = $matches;
if (in_array($_rule, ['value', 'default'])) {
if ($_rule === 'value') $data[$_key] = $value;
if ($_rule === 'default') $data[$_key] = $input[$alias ?: $_key] ?? $value;
if ($_rule === 'value') {
$data[$_key] = $value;
}
if ($_rule === 'default') {
$data[$_key] = $input[$alias ?: $_key] ?? $value;
}
} else {
$info[explode(':', "{$_key}.{$_rule}")[0]] = $value;
$data[$_key] = $data[$_key] ?? ($input[$alias ?: $_key] ?? null);
@ -71,10 +76,10 @@ class ValidateHelper extends Helper
$validate = new Validate();
if ($validate->rule($rule)->message($info)->check($data)) {
return $data;
} elseif (is_callable($callable)) {
return call_user_func($callable, lang($validate->getError()), $data);
} else {
$this->class->error(lang($validate->getError()));
}
if (is_callable($callable)) {
return call_user_func($callable, lang($validate->getError()), $data);
}
$this->class->error(lang($validate->getError()));
}
}
}

View File

@ -1,27 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
use think\admin\Library;
use think\admin\model\SystemBase;
/**
* 动态加载英文数据字典
* 从系统数据字典中读取英文翻译,并缓存以提高性能
* 从系统数据字典中读取英文翻译,并缓存以提高性能.
*/
$cacheKey = 'lang-en-us';
$langs = Library::$sapp->cache->get($cacheKey, []);
@ -29,13 +30,13 @@ $langs = Library::$sapp->cache->get($cacheKey, []);
if (empty($langs)) {
// 从数据字典读取英文翻译
$langs = array_column(SystemBase::items('英文字典'), 'name', 'code');
// 读取英文菜单并合并到语言包中(使用 menus_ 前缀)
$menuItems = array_column(SystemBase::items('英文菜单'), 'name', 'code');
foreach ($menuItems as $key => $name) {
$langs["menus_{$key}"] = $name;
}
// 缓存语言包数据,有效期 360 秒
Library::$sapp->cache->set($cacheKey, $langs, 360);
}
@ -43,43 +44,43 @@ if (empty($langs)) {
/**
* 静态菜单语言包定义
* 使用固定前缀 `menus_` 开头,便于后续扩展和维护
* 注意:该文件仅在英文模式下才会加载,系统默认使用中文模式
* 注意:该文件仅在英文模式下才会加载,系统默认使用中文模式.
*/
$menus = [
// 系统管理菜单
'menus_系统管理' => 'System',
'menus_系统配置' => 'Config',
'menus_系统管理' => 'System',
'menus_系统配置' => 'Config',
'menus_系统参数配置' => 'Params',
'menus_系统任务管理' => 'Tasks',
'menus_系统日志管理' => 'Logs',
'menus_数据字典管理' => 'Dict',
'menus_系统文件管理' => 'Files',
'menus_系统菜单管理' => 'Menus',
'menus_权限管理' => 'Perms',
'menus_权限管理' => 'Perms',
'menus_访问权限管理' => 'Roles',
'menus_系统用户管理' => 'Users',
// 微信管理菜单
'menus_微信管理' => 'WeChat',
'menus_微信管理' => 'WeChat',
'menus_微信接口配置' => 'Config',
'menus_微信支付配置' => 'Pay Config',
'menus_微信粉丝管理' => 'Fans',
'menus_微信定制' => 'Custom',
'menus_微信定制' => 'Custom',
'menus_微信图文管理' => 'News',
'menus_微信菜单配置' => 'Menus',
'menus_回复规则管理' => 'Rules',
'menus_关注自动回复' => 'Auto Reply',
'menus_微信支付' => 'Payment',
'menus_微信支付' => 'Payment',
'menus_支付行为管理' => 'Actions',
'menus_支付退款管理' => 'Refunds',
// 插件中心菜单
'menus_插件中心' => 'Plugins',
'menus_插件中心' => 'Plugins',
];
/**
* 额外语言包配置
* 包含日期格式、登录提示、分页信息等特殊翻译
* 包含日期格式、登录提示、分页信息等特殊翻译.
*/
$extra = [
'Y年m月d日 H:i:s' => 'Y/m/d H:i:s',
@ -89,63 +90,63 @@ $extra = [
/**
* 基础语言包定义
* 包含接口提示、存储引擎、日志记录、模块管理等翻译
* 包含接口提示、存储引擎、日志记录、模块管理等翻译.
*/
$base = [
// 接口提示内容
'数据删除成功!' => 'Deleted successfully.',
'数据删除失败!' => 'Delete failed.',
'数据保存成功!' => 'Saved successfully.',
'数据保存失败!' => 'Save failed.',
'数据排序成功!' => 'Sorted successfully.',
'列表排序失败!' => 'Sort failed.',
'请求响应异常!' => 'Request exception.',
'请求响应成功!' => 'Request successful.',
'未授权禁止访问!' => 'Unauthorized access.',
'会话无效或已失效!' => 'Session invalid or expired.',
'表单令牌验证失败!' => 'Form token validation failed.',
'接口账号验证失败!' => 'Account verification failed.',
'接口请求时差过大!' => 'Request time difference too large.',
'接口签名验证失败!' => 'Signature verification failed.',
'非JWT访问' => 'JWT access required.',
'数据删除成功!' => 'Deleted successfully.',
'数据删除失败!' => 'Delete failed.',
'数据保存成功!' => 'Saved successfully.',
'数据保存失败!' => 'Save failed.',
'数据排序成功!' => 'Sorted successfully.',
'列表排序失败!' => 'Sort failed.',
'请求响应异常!' => 'Request exception.',
'请求响应成功!' => 'Request successful.',
'未授权禁止访问!' => 'Unauthorized access.',
'会话无效或已失效!' => 'Session invalid or expired.',
'表单令牌验证失败!' => 'Form token validation failed.',
'接口账号验证失败!' => 'Account verification failed.',
'接口请求时差过大!' => 'Request time difference too large.',
'接口签名验证失败!' => 'Signature verification failed.',
'非JWT访问' => 'JWT access required.',
'请求参数 %s 不能为空!' => 'Parameter %s cannot be empty.',
'接口请求响应格式异常!' => 'Invalid response format.',
'耗时 %.4f 秒' => 'Time: %.4f s',
'创建任务失败,%s' => 'Failed to create task: %s',
'耗时 %.4f 秒' => 'Time: %.4f s',
'创建任务失败,%s' => 'Failed to create task: %s',
'已创建请等待处理完成!' => 'Task created, please wait.',
'删除%s[%s]及授权配置' => 'Delete %s[%s] and authorization',
'暂无轨迹信息~' => 'No trajectory info.',
'删除%s[%s]及授权配置' => 'Delete %s[%s] and authorization',
'暂无轨迹信息~' => 'No trajectory info.',
// 存储引擎翻译
'本地服务器存储' => 'Local Storage',
'自建Alist存储' => 'Alist Storage',
'又拍云USS存储' => 'Upyun USS',
'阿里云OSS存储' => 'Aliyun OSS',
'腾讯云COS存储' => 'Tencent COS',
'七牛云对象存储' => 'Qiniu OSS',
'未配置又拍云域名' => 'Upyun domain not configured',
'未配置阿里云域名' => 'Aliyun domain not configured',
'未配置七牛云域名' => 'Qiniu domain not configured',
'未配置腾讯云域名' => 'Tencent domain not configured',
'未配置Alist域名' => 'Alist domain not configured',
'本地服务器存储' => 'Local Storage',
'自建Alist存储' => 'Alist Storage',
'又拍云USS存储' => 'Upyun USS',
'阿里云OSS存储' => 'Aliyun OSS',
'腾讯云COS存储' => 'Tencent COS',
'七牛云对象存储' => 'Qiniu OSS',
'未配置又拍云域名' => 'Upyun domain not configured',
'未配置阿里云域名' => 'Aliyun domain not configured',
'未配置七牛云域名' => 'Qiniu domain not configured',
'未配置腾讯云域名' => 'Tencent domain not configured',
'未配置Alist域名' => 'Alist domain not configured',
// 默认日志翻译
'增加%s[%s]成功' => 'Added: %s[%s]',
'修改%s[%s]状态' => 'Modified: %s[%s]',
'更新%s[%s]记录' => 'Updated: %s[%s]',
'删除%s[%s]成功' => 'Deleted: %s[%s]',
'增加%s[%s]成功' => 'Added: %s[%s]',
'修改%s[%s]状态' => 'Modified: %s[%s]',
'更新%s[%s]记录' => 'Updated: %s[%s]',
'删除%s[%s]成功' => 'Deleted: %s[%s]',
// 模块管理翻译
'系统任务管理' => 'Task Management',
'系统菜单管理' => 'Menu Management',
'系统文件管理' => 'File Management',
'系统用户管理' => 'User Management',
'系统日志管理' => 'Logs Management',
'系统参数配置' => 'Parameter Management',
'访问权限管理' => 'Permission Management',
'数据字典管理' => 'Dictionary Management',
'系统运维管理' => 'Maintenance Management',
'系统任务管理' => 'Task Management',
'系统菜单管理' => 'Menu Management',
'系统文件管理' => 'File Management',
'系统用户管理' => 'User Management',
'系统日志管理' => 'Logs Management',
'系统参数配置' => 'Parameter Management',
'访问权限管理' => 'Permission Management',
'数据字典管理' => 'Dictionary Management',
'系统运维管理' => 'Maintenance Management',
];
// 合并所有语言包:基础翻译 -> 额外配置 -> 静态菜单 -> 动态字典
return array_merge($base, $extra, $menus, $langs);
return array_merge($base, $extra, $menus, $langs);

View File

@ -1,27 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
use think\admin\Library;
use think\admin\model\SystemBase;
/**
* 動態加載繁體中文數據字典
* 從系統數據字典中讀取繁體中文翻譯,並緩存以提高性能
* 從系統數據字典中讀取繁體中文翻譯,並緩存以提高性能.
*/
$cacheKey = 'lang-zh-tw';
$langs = Library::$sapp->cache->get($cacheKey, []);
@ -29,20 +30,20 @@ $langs = Library::$sapp->cache->get($cacheKey, []);
if (empty($langs)) {
// 從數據字典讀取繁體中文翻譯
$langs = array_column(SystemBase::items('繁体中文'), 'name', 'code');
// 讀取繁體菜單並合併到語言包中(使用 menus_ 前綴)
$menuItems = array_column(SystemBase::items('繁体菜单'), 'name', 'code');
foreach ($menuItems as $key => $name) {
$langs["menus_{$key}"] = $name;
}
// 緩存語言包數據,有效期 360 秒
Library::$sapp->cache->set($cacheKey, $langs, 360);
}
/**
* 額外語言包配置
* 包含日期格式、登錄提示、分頁信息等特殊翻譯
* 包含日期格式、登錄提示、分頁信息等特殊翻譯.
*/
$extra = [
'Y年m月d日 H:i:s' => 'Y年m月d日 H:i:s',
@ -52,63 +53,63 @@ $extra = [
/**
* 基礎語言包定義
* 包含接口提示、存儲引擎、日誌記錄、模塊管理等翻譯
* 包含接口提示、存儲引擎、日誌記錄、模塊管理等翻譯.
*/
$base = [
// 接口提示內容
'数据删除成功!' => '數據刪除成功!',
'数据删除失败!' => '數據刪除失敗!',
'数据保存成功!' => '數據保存成功!',
'数据保存失败!' => '數據保存失敗!',
'数据排序成功!' => '數據排序成功!',
'列表排序失败!' => '列表排序失敗!',
'请求响应异常!' => '請求響應異常!',
'请求响应成功!' => '請求響應成功!',
'未授权禁止访问!' => '未授權禁止訪問!',
'会话无效或已失效!' => '會話無效或已失效!',
'表单令牌验证失败!' => '表單令牌驗證失敗!',
'接口账号验证失败!' => '接口賬號驗證失敗!',
'接口请求时差过大!' => '接口請求時差過大!',
'接口签名验证失败!' => '接口簽名驗證失敗!',
'非JWT访问' => '請使用 JWT 方式訪問!',
'数据删除成功!' => '數據刪除成功!',
'数据删除失败!' => '數據刪除失敗!',
'数据保存成功!' => '數據保存成功!',
'数据保存失败!' => '數據保存失敗!',
'数据排序成功!' => '數據排序成功!',
'列表排序失败!' => '列表排序失敗!',
'请求响应异常!' => '請求響應異常!',
'请求响应成功!' => '請求響應成功!',
'未授权禁止访问!' => '未授權禁止訪問!',
'会话无效或已失效!' => '會話無效或已失效!',
'表单令牌验证失败!' => '表單令牌驗證失敗!',
'接口账号验证失败!' => '接口賬號驗證失敗!',
'接口请求时差过大!' => '接口請求時差過大!',
'接口签名验证失败!' => '接口簽名驗證失敗!',
'非JWT访问' => '請使用 JWT 方式訪問!',
'请求参数 %s 不能为空!' => '請求參數 %s 不能爲空!',
'接口请求响应格式异常!' => '接口請求響應格式異常!',
'耗时 %.4f 秒' => '耗時 %.4f 秒',
'创建任务失败,%s' => '創建任務失敗,%s',
'耗时 %.4f 秒' => '耗時 %.4f 秒',
'创建任务失败,%s' => '創建任務失敗,%s',
'已创建请等待处理完成!' => '已創建請等待處理完成!',
'删除%s[%s]及授权配置' => '刪除%s[%s]及授權配置',
'暂无轨迹信息~' => '暫無軌迹信息~',
'删除%s[%s]及授权配置' => '刪除%s[%s]及授權配置',
'暂无轨迹信息~' => '暫無軌迹信息~',
// 存儲引擎翻譯
'本地服务器存储' => '本地服務器存儲',
'自建Alist存储' => '自建Alist存儲',
'又拍云USS存储' => '又拍雲USS存儲',
'阿里云OSS存储' => '阿裏雲OSS存儲',
'腾讯云COS存储' => '騰訊雲COS存儲',
'七牛云对象存储' => '七牛雲對象存儲',
'未配置又拍云域名' => '未配置又拍雲域名',
'未配置阿里云域名' => '未配置阿裏雲域名',
'未配置七牛云域名' => '未配置七牛雲域名',
'未配置腾讯云域名' => '未配置騰訊雲域名',
'未配置Alist域名' => '未配置Alist域名',
'本地服务器存储' => '本地服務器存儲',
'自建Alist存储' => '自建Alist存儲',
'又拍云USS存储' => '又拍雲USS存儲',
'阿里云OSS存储' => '阿裏雲OSS存儲',
'腾讯云COS存储' => '騰訊雲COS存儲',
'七牛云对象存储' => '七牛雲對象存儲',
'未配置又拍云域名' => '未配置又拍雲域名',
'未配置阿里云域名' => '未配置阿裏雲域名',
'未配置七牛云域名' => '未配置七牛雲域名',
'未配置腾讯云域名' => '未配置騰訊雲域名',
'未配置Alist域名' => '未配置Alist域名',
// 默認日誌翻譯
'增加%s[%s]成功' => '增加%s[%s]成功',
'修改%s[%s]状态' => '修改%s[%s]狀態',
'更新%s[%s]记录' => '更新%s[%s]記錄',
'删除%s[%s]成功' => '刪除%s[%s]成功',
'增加%s[%s]成功' => '增加%s[%s]成功',
'修改%s[%s]状态' => '修改%s[%s]狀態',
'更新%s[%s]记录' => '更新%s[%s]記錄',
'删除%s[%s]成功' => '刪除%s[%s]成功',
// 模塊管理翻譯
'系统任务管理' => '系統任務管理',
'系统菜单管理' => '系統菜單管理',
'系统文件管理' => '系統文件管理',
'系统用户管理' => '系統用戶管理',
'系统日志管理' => '系統日誌管理',
'系统参数配置' => '系統參數配置',
'访问权限管理' => '訪問權限管理',
'数据字典管理' => '數據字典管理',
'系统运维管理' => '系統運維管理',
'系统任务管理' => '系統任務管理',
'系统菜单管理' => '系統菜單管理',
'系统文件管理' => '系統文件管理',
'系统用户管理' => '系統用戶管理',
'系统日志管理' => '系統日誌管理',
'系统参数配置' => '系統參數配置',
'访问权限管理' => '訪問權限管理',
'数据字典管理' => '數據字典管理',
'系统运维管理' => '系統運維管理',
];
// 合併所有語言包:基礎翻譯 -> 額外配置 -> 動態字典
return array_merge($base, $extra, $langs);
return array_merge($base, $extra, $langs);

View File

@ -1,27 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 用户权限模型
* 用户权限模型.
*
* @property int $id
* @property int $sort 排序权重
@ -31,31 +36,30 @@ use think\admin\Model;
* @property string $title 权限名称
* @property string $utype 身份权限
* @class SystemAuth
* @package think\admin\model
*/
class SystemAuth extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 日志名称
* 日志名称.
* @var string
*/
protected $oplogName = '系统权限';
/**
* 日志类型
* 日志类型.
* @var string
*/
protected $oplogType = '系统权限管理';
/**
* 获取权限数据
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* 获取权限数据.
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function items(): array
{
@ -63,22 +67,22 @@ class SystemAuth extends Model
}
/**
* 删除权限事件
* @param string $ids
* 删除权限事件.
*/
public function onAdminDelete(string $ids)
{
if (count($aids = str2arr($ids)) > 0) SystemNode::mk()->whereIn('auth', $aids)->delete();
sysoplog($this->oplogType, lang("删除%s[%s]及授权配置", [lang($this->oplogName), $ids]));
if (count($aids = str2arr($ids)) > 0) {
SystemNode::mk()->whereIn('auth', $aids)->delete();
}
sysoplog($this->oplogType, lang('删除%s[%s]及授权配置', [lang($this->oplogName), $ids]));
}
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,27 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 数据字典模型
* 数据字典模型.
*
* @property int $deleted 删除状态(0正常,1已删)
* @property int $deleted_by 删除用户
@ -35,60 +37,63 @@ use think\admin\Model;
* @property string $name 数据名称
* @property string $type 数据类型
* @class SystemBase
* @package think\admin\model
*/
class SystemBase extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 日志名称
* 日志名称.
* @var string
*/
protected $oplogName = '数据字典';
/**
* 日志类型
* 日志类型.
* @var string
*/
protected $oplogType = '数据字典管理';
/**
* 获取指定数据列表
* 获取指定数据列表.
* @param string $type 数据类型
* @param array $data 外围数据
* @param string $field 外链字段
* @param string $bind 绑定字段
* @return array
*/
public static function items(string $type, array &$data = [], string $field = 'base_code', string $bind = 'base_info'): array
{
$map = ['type' => $type, 'status' => 1, 'deleted' => 0];
$bases = static::mk()->where($map)->order('sort desc,id asc')->column('code,name,content', 'code');
if (count($data) > 0) foreach ($data as &$vo) $vo[$bind] = $bases[$vo[$field]] ?? [];
if (count($data) > 0) {
foreach ($data as &$vo) {
$vo[$bind] = $bases[$vo[$field]] ?? [];
}
}
return $bases;
}
/**
* 获取所有数据类型
* @param boolean $simple 加载默认值
* @return array
* 获取所有数据类型.
* @param bool $simple 加载默认值
*/
public static function types(bool $simple = false): array
{
$types = static::mk()->where(['deleted' => 0])->distinct()->column('type');
if (empty($types) && empty($simple)) $types = ['身份权限'];
if (empty($types) && empty($simple)) {
$types = ['身份权限'];
}
return $types;
}
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,37 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 系统配置模型
* 系统配置模型.
*
* @property int $id
* @property string $name 配置名称
* @property string $type 配置分类
* @property string $value 配置内容
* @class SystemConfig
* @package think\admin\model
*/
class SystemConfig extends Model
{
protected $updateTime = false;
protected $createTime = false;
}
}

View File

@ -1,27 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 系统数据模型
* 系统数据模型.
*
* @property int $id
* @property string $create_time 创建时间
@ -29,8 +31,5 @@ use think\admin\Model;
* @property string $update_time 更新时间
* @property string $value 配置值
* @class SystemData
* @package think\admin\model
*/
class SystemData extends Model
{
}
class SystemData extends Model {}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
@ -41,27 +43,25 @@ use think\model\relation\HasOne;
* @property string $xext 文件后缀
* @property string $xkey 文件路径
* @property string $xurl 访问链接
* @property-read \think\admin\model\SystemUser $user
* @property SystemUser $user
* @class SystemFile
* @package think\admin\model
*/
class SystemFile extends Model
{
/**
* 创建字段
* 创建字段.
* @var string
*/
protected $createTime = 'create_at';
/**
* 更新字段
* 更新字段.
* @var string
*/
protected $updateTime = 'update_at';
/**
* 关联用户数据
* @return \think\model\relation\HasOne
* 关联用户数据.
*/
public function user(): HasOne
{
@ -69,9 +69,8 @@ class SystemFile extends Model
}
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
@ -79,12 +78,11 @@ class SystemFile extends Model
}
/**
* 格式化更新时间
* 格式化更新时间.
* @param mixed $value
* @return string
*/
public function getUpdateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,27 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 系统菜单模型
* 系统菜单模型.
*
* @property int $id
* @property int $pid 上级ID
@ -35,32 +37,31 @@ use think\admin\Model;
* @property string $title 菜单名称
* @property string $url 链接节点
* @class SystemMenu
* @package think\admin\model
*/
class SystemMenu extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 日志名称
* 日志名称.
* @var string
*/
protected $oplogName = '系统菜单';
/**
* 日志类型
* 日志类型.
* @var string
*/
protected $oplogType = '系统菜单管理';
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,43 +1,45 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 授权节点模型
* 授权节点模型.
*
* @property int $auth 角色
* @property int $id
* @property string $node 节点
* @class SystemNode
* @mixin \think\db\Query
* @package think\admin\model
*/
class SystemNode extends Model
{
protected $updateTime = false;
protected $createTime = false;
/**
* 绑定模型名称
* 绑定模型名称.
* @var string
*/
protected $name = 'SystemAuthNode';
}
}

View File

@ -1,27 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 系统日志模型
* 系统日志模型.
*
* @property int $id
* @property string $action 操作行为名称
@ -31,20 +33,19 @@ use think\admin\Model;
* @property string $node 当前操作节点
* @property string $username 操作人用户名
* @class SystemOplog
* @package think\admin\model
*/
class SystemOplog extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,27 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
use think\admin\Model;
/**
* 系统任务模型
* 系统任务模型.
*
* @property int $attempts 执行次数
* @property int $exec_pid 执行进程
@ -40,17 +42,16 @@ use think\admin\Model;
* @property string $outer_time 结束时间
* @property string $title 任务名称
* @class SystemQueue
* @package think\admin\model
*/
class SystemQueue extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 格式化计划时间
* 格式化计划时间.
* @param mixed $value
* @return string
*/
public function getExecTimeAttr($value): string
{
@ -58,9 +59,8 @@ class SystemQueue extends Model
}
/**
* 执行开始时间处理
* 执行开始时间处理.
* @param mixed $value
* @return string
*/
public function getEnterTimeAttr($value): string
{
@ -68,27 +68,23 @@ class SystemQueue extends Model
}
/**
* 执行结束时间处理
* 执行结束时间处理.
* @param mixed $value
* @param array $data
* @return string
*/
public function getOuterTimeAttr($value, array $data): string
{
if ($value > 0 && $value > $data['enter_time']) {
return lang("耗时 %.4f 秒", [$data['outer_time'] - $data['enter_time']]);
} else {
return ' - ';
return lang('耗时 %.4f 秒', [$data['outer_time'] - $data['enter_time']]);
}
return ' - ';
}
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\model;
@ -22,7 +24,7 @@ use think\admin\Model;
use think\model\relation\HasOne;
/**
* 系统用户模型
* 系统用户模型.
*
* @property int $id
* @property int $is_deleted 删除(1删除,0未删)
@ -42,51 +44,50 @@ use think\model\relation\HasOne;
* @property string $password 用户密码
* @property string $username 用户账号
* @property string $usertype 用户类型
* @property-read \think\admin\model\SystemBase $userinfo
* @property SystemBase $userinfo
* @class SystemUser
* @package think\admin\model
*/
class SystemUser extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
/**
* 日志名称
* 日志名称.
* @var string
*/
protected $oplogName = '系统用户';
/**
* 日志类型
* 日志类型.
* @var string
*/
protected $oplogType = '系统用户管理';
/**
* 获取用户数据
* 获取用户数据.
* @param mixed $map 数据查询规则
* @param array $data 用户数据集合
* @param string $field 原外连字段
* @param string $target 关联目标字段
* @param string $fields 关联数据字段
* @return array
*/
public static function items($map, array &$data = [], string $field = 'uuid', string $target = 'user_info', string $fields = 'username,nickname,headimg,status,is_deleted'): array
{
$query = static::mk()->where($map)->order('sort desc,id desc');
if (count($data) > 0) {
$users = $query->whereIn('id', array_unique(array_column($data, $field)))->column($fields, 'id');
foreach ($data as &$vo) $vo[$target] = $users[$vo[$field]] ?? [];
foreach ($data as &$vo) {
$vo[$target] = $users[$vo[$field]] ?? [];
}
return $users;
} else {
return $query->column($fields, 'id');
}
return $query->column($fields, 'id');
}
/**
* 关联身份权限
* @return HasOne
* 关联身份权限.
*/
public function userinfo(): HasOne
{
@ -96,26 +97,25 @@ class SystemUser extends Model
}
/**
* 默认头像处理
* 默认头像处理.
* @param mixed $value
* @return string
*/
public function getHeadimgAttr($value): string
{
if (empty($value)) try {
$host = sysconf('base.site_host|raw') ?: 'https://v6.thinkadmin.top';
return "{$host}/static/theme/img/headimg.png";
} catch (\Exception $exception) {
return "https://v6.thinkadmin.top/static/theme/img/headimg.png";
if (empty($value)) {
try {
$host = sysconf('base.site_host|raw') ?: 'https://v6.thinkadmin.top';
return "{$host}/static/theme/img/headimg.png";
} catch (\Exception $exception) {
return 'https://v6.thinkadmin.top/static/theme/img/headimg.png';
}
} else {
return $value;
}
}
/**
* 格式化登录时间
* @param string $value
* @return string
* 格式化登录时间.
*/
public function getLoginAtAttr(string $value): string
{
@ -123,12 +123,11 @@ class SystemUser extends Model
}
/**
* 格式化创建时间
* 格式化创建时间.
* @param mixed $value
* @return string
*/
public function getCreateAtAttr($value): string
{
return format_datetime($value);
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -32,19 +34,40 @@ use think\Session;
/**
* 系统权限管理服务
* @class AdminService
* @package think\admin\service
*/
class AdminService extends Service
{
/**
* 自定义回调处理
* 自定义回调处理.
* @var array
*/
private static $checkCallables = [];
/**
* 是否已经登录
* @return boolean
* 静态方法兼容(临时).
* @return bool
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if (strtolower($method) === 'clearcache') {
return static::clear();
}
throw new Exception("method not exists: AdminService::{$method}()");
}
/**
* 对象方法兼容(临时).
* @return bool
* @throws Exception
*/
public function __call(string $method, array $arguments)
{
return static::__callStatic($method, $arguments);
}
/**
* 是否已经登录.
*/
public static function isLogin(): bool
{
@ -52,8 +75,7 @@ class AdminService extends Service
}
/**
* 是否为超级用户
* @return boolean
* 是否为超级用户.
*/
public static function isSuper(): bool
{
@ -61,8 +83,7 @@ class AdminService extends Service
}
/**
* 获取超级用户账号
* @return string
* 获取超级用户账号.
*/
public static function getSuperName(): string
{
@ -70,8 +91,7 @@ class AdminService extends Service
}
/**
* 获取后台用户ID
* @return integer
* 获取后台用户ID.
*/
public static function getUserId(): int
{
@ -79,8 +99,7 @@ class AdminService extends Service
}
/**
* 获取后台用户名称
* @return string
* 获取后台用户名称.
*/
public static function getUserName(): string
{
@ -88,8 +107,7 @@ class AdminService extends Service
}
/**
* 获取用户扩展数据
* @param null|string $field
* 获取用户扩展数据.
* @param null|mixed $default
* @return array|mixed
*/
@ -100,11 +118,8 @@ class AdminService extends Service
}
/**
* 设置用户扩展数据
* @param array $data
* @param boolean $replace
* @return boolean
* @throws \think\admin\Exception
* 设置用户扩展数据.
* @throws Exception
*/
public static function setUserData(array $data, bool $replace = false): bool
{
@ -113,9 +128,8 @@ class AdminService extends Service
}
/**
* 获取用户主题名称
* @return string
* @throws \think\admin\Exception
* 获取用户主题名称.
* @throws Exception
*/
public static function getUserTheme(): string
{
@ -124,10 +138,9 @@ class AdminService extends Service
}
/**
* 设置用户主题名称
* 设置用户主题名称.
* @param string $theme 主题名称
* @return boolean
* @throws \think\admin\Exception
* @throws Exception
*/
public static function setUserTheme(string $theme): bool
{
@ -135,9 +148,7 @@ class AdminService extends Service
}
/**
* 注册权限检查函数
* @param callable $callable
* @return integer
* 注册权限检查函数.
*/
public static function registerCheckCallable(callable $callable): int
{
@ -146,28 +157,24 @@ class AdminService extends Service
}
/**
* 移除权限检查函数
* @param ?integer $index
* @return boolean
* 移除权限检查函数.
*/
public static function removeCheckCallable(?int $index): bool
{
if (is_null($index)) {
self::$checkCallables = [];
return true;
} elseif (isset(self::$checkCallables[$index])) {
}
if (isset(self::$checkCallables[$index])) {
unset(self::$checkCallables[$index]);
return true;
} else {
return false;
}
return false;
}
/**
* 检查指定节点授权
* --- 需要读取缓存或扫描所有节点
* @param null|string $node
* @return boolean
* --- 需要读取缓存或扫描所有节点.
*/
public static function check(?string $node = ''): bool
{
@ -189,23 +196,24 @@ class AdminService extends Service
return call_user_func('admin_check_filter', $current, $methods, $userNodes);
}
// 超级用户不需要检查权限
if (static::isSuper()) return true;
if (static::isSuper()) {
return true;
}
// 节点权限检查,需要兼容 windows 控制器不区分大小写,统一去除节点下划线再检查权限
if (empty($simples = sysvar($skey2 = 'think.admin.fulls') ?: [])) {
foreach ($methods as $k => $v) $simples[strtr($k, ['_' => ''])] = $v;
foreach ($methods as $k => $v) {
$simples[strtr($k, ['_' => ''])] = $v;
}
sysvar($skey2, $simples);
}
if (empty($simples[$simple = strtr($current, ['_' => ''])]['isauth'])) {
return !(!empty($simples[$simple]['islogin']) && !static::isLogin());
} else {
return in_array($current, $userNodes);
}
return in_array($current, $userNodes);
}
/**
* 获取授权节点列表
* @param array $checkeds
* @return array
* 获取授权节点列表.
*/
public static function getTree(array $checkeds = []): array
{
@ -219,27 +227,36 @@ class AdminService extends Service
$nodes[$node] = ['node' => $node, 'title' => lang($method['title']), 'pnode' => $pnode, 'checked' => in_array($node, $checkeds)];
}
}
foreach (array_keys($nodes) as $key) foreach ($methods as $node => $method) if (stripos($key, $node . '/') !== false) {
$pnode = substr($node, 0, strripos($node, '/'));
$nodes[$node] = ['node' => $node, 'title' => lang($method['title']), 'pnode' => $pnode, 'checked' => in_array($node, $checkeds)];
$nodes[$pnode] = ['node' => $pnode, 'title' => Str::studly($pnode), 'pnode' => '', 'checked' => in_array($pnode, $checkeds)];
foreach (array_keys($nodes) as $key) {
foreach ($methods as $node => $method) {
if (stripos($key, $node . '/') !== false) {
$pnode = substr($node, 0, strripos($node, '/'));
$nodes[$node] = ['node' => $node, 'title' => lang($method['title']), 'pnode' => $pnode, 'checked' => in_array($node, $checkeds)];
$nodes[$pnode] = ['node' => $pnode, 'title' => Str::studly($pnode), 'pnode' => '', 'checked' => in_array($pnode, $checkeds)];
}
}
}
return DataExtend::arr2tree(array_reverse($nodes), 'node', 'pnode', '_sub_');
}
/**
* 初始化用户权限
* @param boolean $force 强刷权限
* @return array
* 初始化用户权限.
* @param bool $force 强刷权限
*/
public static function apply(bool $force = false): array
{
if ($force) static::clear();
if (($uuid = static::getUserId()) <= 0) return [];
if ($force) {
static::clear();
}
if (($uuid = static::getUserId()) <= 0) {
return [];
}
$user = SystemUser::mk()->where(['id' => $uuid])->findOrEmpty()->toArray();
if (!static::isSuper() && count($aids = str2arr($user['authorize'])) > 0) {
$aids = SystemAuth::mk()->where(['status' => 1])->whereIn('id', $aids)->column('id');
if (!empty($aids)) $nodes = SystemNode::mk()->distinct()->whereIn('auth', $aids)->column('node');
if (!empty($aids)) {
$nodes = SystemNode::mk()->distinct()->whereIn('auth', $aids)->column('node');
}
}
$user['nodes'] = $nodes ?? [];
Library::$sapp->session->set('user', $user);
@ -247,8 +264,7 @@ class AdminService extends Service
}
/**
* 清理节点缓存
* @return bool
* 清理节点缓存.
*/
public static function clear(): bool
{
@ -257,18 +273,21 @@ class AdminService extends Service
}
/**
* 获取会员上传配置
* @param ?string $uptoken
* 获取会员上传配置.
* @return array [unid,exts]
*/
public static function withUploadUnid(?string $uptoken = null): array
{
try {
if ($uptoken === '') return [0, []];
if ($uptoken === '') {
return [0, []];
}
$session = Library::$sapp->session;
if (is_null($uptoken)) {
$sesskey = $session->get('UploadSessionKey');
if (empty($sesskey)) return [0, []];
if (empty($sesskey)) {
return [0, []];
}
if ($session->getId() !== $sesskey) {
$session = Library::$sapp->invokeClass(Session::class);
$session->setId($sesskey);
@ -277,7 +296,9 @@ class AdminService extends Service
$unid = intval($session->get('AdminUploadUnid', 0));
} else {
$sesskey = CodeExtend::decrypt($uptoken, sysconf('data.jwtkey'));
if (empty($sesskey)) return [0, []];
if (empty($sesskey)) {
return [0, []];
}
if ($session->getId() !== $sesskey) {
$session = Library::$sapp->invokeClass(Session::class);
$session->setId($sesskey);
@ -294,11 +315,10 @@ class AdminService extends Service
}
/**
* 生成上传入口令牌
* @param integer $unid 会员编号
* 生成上传入口令牌.
* @param int $unid 会员编号
* @param string $exts 允许后缀(多个以英文逗号隔开)
* @return string
* @throws \think\admin\Exception
* @throws Exception
*/
public static function withUploadToken(int $unid, string $exts = ''): string
{
@ -306,29 +326,4 @@ class AdminService extends Service
Library::$sapp->session->set('AdminUploadExts', str2arr(strtolower($exts)));
return CodeExtend::encrypt(Library::$sapp->session->getId(), sysconf('data.jwtkey'));
}
/**
* 静态方法兼容(临时)
* @param string $method
* @param array $arguments
* @return bool
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if (strtolower($method) === 'clearcache') return static::clear();
throw new Exception("method not exists: AdminService::{$method}()");
}
/**
* 对象方法兼容(临时)
* @param string $method
* @param array $arguments
* @return bool
* @throws \think\admin\Exception
*/
public function __call(string $method, array $arguments)
{
return static::__callStatic($method, $arguments);
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -24,90 +26,23 @@ use think\admin\Service;
/**
* 图形验证码服务
* @class CaptchaService
* @package think\admin\service
*/
class CaptchaService extends Service
{
private $code; // 验证码
private $uniqid; // 唯一序号
private $charset = 'ABCDEFGHKMNPRSTUVWXYZ23456789'; // 随机因子
private $width = 130; // 图片宽度
private $height = 50; // 图片高度
private $length = 4; // 验证码长度
private $fontsize = 20; // 指定字体大小
/**
* 验证码服务初始化
* @param array $config
* @return static
*/
public function initialize(array $config = []): CaptchaService
{
// 动态配置属性
foreach ($config as $k => $v) if (isset($this->$k)) $this->$k = $v;
// 生成验证码序号
$this->uniqid = uniqid('captcha') . mt_rand(1000, 9999);
// 生成验证码字符串
[$this->code, $length] = ['', strlen($this->charset) - 1];
for ($i = 0; $i < $this->length; $i++) {
$this->code .= $this->charset[mt_rand(0, $length)];
}
// 缓存验证码字符串
$this->app->cache->set($this->uniqid, $this->code, 360);
// 返回当前对象
return $this;
}
/**
* 动态切换配置
* @param array $config
* @return $this
*/
public function config(array $config = []): CaptchaService
{
return $this->initialize($config);
}
/**
* 获取验证码值
* @return string
*/
public function getCode(): string
{
return $this->code;
}
/**
* 获取图片的内容
* @return string
*/
public function getData(): string
{
return "data:image/png;base64,{$this->_image()}";
}
/**
* 获取验证码编号
* @return string
*/
public function getUniqid(): string
{
return $this->uniqid;
}
/**
* 获取验证码数据
* @return array
*/
public function getAttrs(): array
{
return [
'code' => $this->getCode(),
'data' => $this->getData(),
'uniqid' => $this->getUniqid(),
];
}
/**
* 输出图形验证码
* @return string
@ -118,8 +53,101 @@ class CaptchaService extends Service
}
/**
* 创建验证码图片
* @return string
* 验证码服务初始化.
* @return static
*/
public function initialize(array $config = []): CaptchaService
{
// 动态配置属性
foreach ($config as $k => $v) {
if (isset($this->{$k})) {
$this->{$k} = $v;
}
}
// 生成验证码序号
$this->uniqid = uniqid('captcha') . mt_rand(1000, 9999);
// 生成验证码字符串
[$this->code, $length] = ['', strlen($this->charset) - 1];
for ($i = 0; $i < $this->length; ++$i) {
$this->code .= $this->charset[mt_rand(0, $length)];
}
// 缓存验证码字符串
$this->app->cache->set($this->uniqid, $this->code, 360);
// 返回当前对象
return $this;
}
/**
* 动态切换配置.
* @return $this
*/
public function config(array $config = []): CaptchaService
{
return $this->initialize($config);
}
/**
* 获取验证码值
*/
public function getCode(): string
{
return $this->code;
}
/**
* 获取图片的内容.
*/
public function getData(): string
{
return "data:image/png;base64,{$this->_image()}";
}
/**
* 获取验证码编号.
*/
public function getUniqid(): string
{
return $this->uniqid;
}
/**
* 获取验证码数据.
*/
public function getAttrs(): array
{
return [
'code' => $this->getCode(),
'data' => $this->getData(),
'uniqid' => $this->getUniqid(),
];
}
/**
* 获取字体文件.
*/
public static function font(): string
{
return __DIR__ . '/bin/captcha.ttf';
}
/**
* 检查验证码是否正确.
* @param string $code 需要验证的值
* @param null|string $uniqid 验证码编号
*/
public static function check(string $code, ?string $uniqid = null): bool
{
$_uni = is_string($uniqid) ? $uniqid : input('uniqid', '-');
$_val = Library::$sapp->cache->get($_uni, '');
if (is_string($_val) && strtolower($_val) === strtolower($code)) {
Library::$sapp->cache->delete($_uni);
return true;
}
return false;
}
/**
* 创建验证码图片.
*/
private function _image(): string
{
@ -128,19 +156,19 @@ class CaptchaService extends Service
$color = imagecolorallocate($img, mt_rand(220, 255), mt_rand(220, 255), mt_rand(220, 255));
imagefilledrectangle($img, 0, $this->height, $this->width, 0, $color);
// 生成线条
for ($i = 0; $i < 6; $i++) {
for ($i = 0; $i < 6; ++$i) {
$color = imagecolorallocate($img, mt_rand(0, 50), mt_rand(0, 50), mt_rand(0, 50));
imageline($img, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
}
// 生成雪花
for ($i = 0; $i < 100; $i++) {
for ($i = 0; $i < 100; ++$i) {
$color = imagecolorallocate($img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
imagestring($img, mt_rand(1, 5), mt_rand(0, $this->width), mt_rand(0, $this->height), '*', $color);
}
// 生成文字
$_x = $this->width / $this->length;
$fontfile = self::font();
for ($i = 0; $i < $this->length; $i++) {
for ($i = 0; $i < $this->length; ++$i) {
$fontcolor = imagecolorallocate($img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156));
if (function_exists('imagettftext')) {
imagettftext($img, $this->fontsize, mt_rand(-30, 30), intval($_x * $i + mt_rand(1, 5)), intval($this->height / 1.4), $fontcolor, $fontfile, $this->code[$i]);
@ -157,31 +185,4 @@ class CaptchaService extends Service
}
return base64_encode($data);
}
/**
* 获取字体文件
* @return string
*/
public static function font(): string
{
return __DIR__ . '/bin/captcha.ttf';
}
/**
* 检查验证码是否正确
* @param string $code 需要验证的值
* @param null|string $uniqid 验证码编号
* @return boolean
*/
public static function check(string $code, ?string $uniqid = null): bool
{
$_uni = is_string($uniqid) ? $uniqid : input('uniqid', '-');
$_val = Library::$sapp->cache->get($_uni, '');
if (is_string($_val) && strtolower($_val) === strtolower($code)) {
Library::$sapp->cache->delete($_uni);
return true;
} else {
return false;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -23,40 +25,79 @@ use think\admin\extend\HttpExtend;
use think\admin\Service;
/**
* 百度快递100物流查询
* 百度快递100物流查询.
* @class ExpressService
* @deprecated 独立封装为插件
* @package think\admin\service
*/
class ExpressService extends Service
{
/**
* 网络请求参数
* 网络请求参数.
* @var array
*/
protected $options = [];
/**
* 公司编码别名
* 公司编码别名.
* @var array
*/
protected $codes = [
'YD' => 'yunda',
'SF' => 'shunfeng',
'UC' => 'youshuwuliu',
'YTO' => 'yuantong',
'STO' => 'shentong',
'ZTO' => 'zhongtong',
'ZJS' => 'zhaijisong',
'DBL' => 'debangwuliu',
'YD' => 'yunda',
'SF' => 'shunfeng',
'UC' => 'youshuwuliu',
'YTO' => 'yuantong',
'STO' => 'shentong',
'ZTO' => 'zhongtong',
'ZJS' => 'zhaijisong',
'DBL' => 'debangwuliu',
'HHTT' => 'tiantian',
'HTKY' => 'huitongkuaidi',
'YZPY' => 'youzhengguonei',
];
/**
* 快递服务初始化
* 通过百度快递100应用查询物流信息.
* @param string $code 快递公司编辑
* @param string $number 快递物流编号
* @param array $list 快递路径列表
*/
public function express(string $code, string $number, array $list = []): array
{
// 新状态1-新订单,2-在途中,3-签收,4-问题件
// 原状态0-在途1-揽收2-疑难3-签收4-退签5-派件6-退回7-转投8-清关14-拒签
$ckey = md5("{$code}{$number}");
$cache = $this->app->cache->get($ckey, []);
$message = [1 => '新订单', 2 => '在途中', 3 => '签收', 4 => '问题件'];
if (!empty($cache)) {
return $cache;
}
for ($i = 0; $i < 6; ++$i) {
if (is_array($result = $this->doExpress($code, $number))) {
if (isset($result['data']['info']['context'], $result['data']['info']['state'])) {
$state = intval($result['data']['info']['state']);
$status = in_array($state, [0, 1, 5, 7, 8]) ? 2 : ($state === 3 ? 3 : 4);
foreach ($result['data']['info']['context'] as $vo) {
$list[] = ['time' => date('Y-m-d H:i:s', intval($vo['time'])), 'context' => $vo['desc']];
}
$result = ['message' => lang($message[$status] ?? $result['msg']), 'status' => $status, 'express' => $code, 'number' => $number, 'data' => $list];
$this->app->cache->set($ckey, $result, 30);
return $result;
}
}
}
return ['message' => lang('暂无轨迹信息~'), 'status' => 1, 'express' => $code, 'number' => $number, 'data' => $list];
}
/**
* 获取快递公司列表.
*/
public function getExpressList(): array
{
return $this->getQueryData(2);
}
/**
* 快递服务初始化.
* @return $this
*/
protected function initialize(): ExpressService
@ -72,43 +113,6 @@ class ExpressService extends Service
return $this;
}
/**
* 通过百度快递100应用查询物流信息
* @param string $code 快递公司编辑
* @param string $number 快递物流编号
* @param array $list 快递路径列表
* @return array
*/
public function express(string $code, string $number, array $list = []): array
{
// 新状态1-新订单,2-在途中,3-签收,4-问题件
// 原状态0-在途1-揽收2-疑难3-签收4-退签5-派件6-退回7-转投8-清关14-拒签
$ckey = md5("{$code}{$number}");
$cache = $this->app->cache->get($ckey, []);
$message = [1 => '新订单', 2 => '在途中', 3 => '签收', 4 => '问题件'];
if (!empty($cache)) return $cache;
for ($i = 0; $i < 6; $i++) if (is_array($result = $this->doExpress($code, $number))) {
if (isset($result['data']['info']['context']) && isset($result['data']['info']['state'])) {
$state = intval($result['data']['info']['state']);
$status = in_array($state, [0, 1, 5, 7, 8]) ? 2 : ($state === 3 ? 3 : 4);
foreach ($result['data']['info']['context'] as $vo) $list[] = ['time' => date('Y-m-d H:i:s', intval($vo['time'])), 'context' => $vo['desc']];
$result = ['message' => lang($message[$status] ?? $result['msg']), 'status' => $status, 'express' => $code, 'number' => $number, 'data' => $list];
$this->app->cache->set($ckey, $result, 30);
return $result;
}
}
return ['message' => lang('暂无轨迹信息~'), 'status' => 1, 'express' => $code, 'number' => $number, 'data' => $list];
}
/**
* 获取快递公司列表
* @return array
*/
public function getExpressList(): array
{
return $this->getQueryData(2);
}
/**
* 执行百度快递100应用查询请求
* @param string $code 快递公司编号
@ -129,17 +133,21 @@ class ExpressService extends Service
}
/**
* 获取快递查询接口
* @param integer $type 类型数据
* @return string|array
* 获取快递查询接口.
* @param int $type 类型数据
* @return array|string
*/
private function getQueryData(int $type)
{
$times = 0;
$expressUri = $this->app->cache->get('express_kuaidi_uri', '');
if ($type == 1 && !empty($expressUri)) return $expressUri;
if ($type == 1 && !empty($expressUri)) {
return $expressUri;
}
$expressCom = $this->app->cache->get('express_kuaidi_com', []);
if ($type === 2 && !empty($expressCom)) return $expressCom;
if ($type === 2 && !empty($expressCom)) {
return $expressCom;
}
while (true) {
if ($times++ >= 10) {
$times = 0;
@ -153,10 +161,16 @@ class ExpressService extends Service
$attr = json_decode($items[1], true);
$expressCom = array_combine(array_column($attr, 'value'), array_column($attr, 'text'));
$this->app->cache->set('express_kuaidi_com', $expressCom, 3600);
if ($type === 2) return $expressCom;
if ($type === 2) {
return $expressCom;
}
}
if ($type === 1) return $expressUri;
} else usleep(100000);
if ($type === 1) {
return $expressUri;
}
} else {
usleep(100000);
}
}
}
}
}

View File

@ -1,24 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
use stdClass;
use think\admin\Exception;
use think\admin\extend\HttpExtend;
use think\admin\helper\ValidateHelper;
@ -29,24 +30,23 @@ use think\exception\HttpResponseException;
/**
* 通用接口基础服务
* @class InterfaceService
* @package think\admin\service
*/
class InterfaceService extends Service
{
/**
* 输出格式
* 输出格式.
* @var string
*/
private $type = 'json';
/**
* 接口认证账号
* 接口认证账号.
* @var string
*/
private $appid;
/**
* 接口认证密钥
* 接口认证密钥.
* @var string
*/
private $appkey;
@ -60,8 +60,7 @@ class InterfaceService extends Service
/**
* 接口服务初始化
* InterfaceService constructor.
* @param App $app
* @throws \think\admin\Exception
* @throws Exception
*/
public function __construct(App $app)
{
@ -72,7 +71,7 @@ class InterfaceService extends Service
}
/**
* 设置接口网关
* 设置接口网关.
* @param string $getway 接口网关
* @return $this
*/
@ -83,7 +82,7 @@ class InterfaceService extends Service
}
/**
* 设置授权账号
* 设置授权账号.
* @param string $appid 接口账号
* @param string $appkey 接口密钥
* @return $this
@ -96,7 +95,7 @@ class InterfaceService extends Service
}
/**
* 设置输出类型为 JSON
* 设置输出类型为 JSON.
* @return $this
*/
public function setOutTypeJson(): InterfaceService
@ -106,7 +105,7 @@ class InterfaceService extends Service
}
/**
* 设置输出类型为 Array
* 设置输出类型为 Array.
* @return $this
*/
public function setOutTypeArray(): InterfaceService
@ -116,8 +115,7 @@ class InterfaceService extends Service
}
/**
* 获取当前APPID
* @return string
* 获取当前APPID.
*/
public function getAppid(): string
{
@ -125,16 +123,15 @@ class InterfaceService extends Service
}
/**
* 获取请求参数
* @return array
* 获取请求参数.
*/
public function getData(): array
{
// 基础参数获取
$input = ValidateHelper::instance()->init([
'time.require' => lang('请求参数 %s 不能为空!', ['time']),
'sign.require' => lang('请求参数 %s 不能为空!', ['sign']),
'data.require' => lang('请求参数 %s 不能为空!', ['data']),
'time.require' => lang('请求参数 %s 不能为空!', ['time']),
'sign.require' => lang('请求参数 %s 不能为空!', ['sign']),
'data.require' => lang('请求参数 %s 不能为空!', ['data']),
'appid.require' => lang('请求参数 %s 不能为空!', ['appid']),
'nostr.require' => lang('请求参数 %s 不能为空!', ['nostr']),
], 'post', [$this, 'baseError']);
@ -155,35 +152,39 @@ class InterfaceService extends Service
}
/**
* 回复业务处理失败的消息
* 回复业务处理失败的消息.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 返回状态码
*/
public function error($info, $data = '{-null-}', $code = 0): void
{
if ($data === '{-null-}') $data = new stdClass();
if ($data === '{-null-}') {
$data = new \stdClass();
}
$this->baseResponse(lang('请求响应异常!'), [
'code' => $code, 'info' => $info, 'data' => $data,
]);
}
/**
* 回复业务处理成功的消息
* 回复业务处理成功的消息.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 返回状态码
*/
public function success($info, $data = '{-null-}', $code = 1): void
{
if ($data === '{-null-}') $data = new stdClass();
if ($data === '{-null-}') {
$data = new \stdClass();
}
$this->baseResponse(lang('请求响应成功!'), [
'code' => $code, 'info' => is_string($info) ? lang($info) : $info, 'data' => $data,
]);
}
/**
* 回复根失败消息
* 回复根失败消息.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 根状态码
@ -194,7 +195,7 @@ class InterfaceService extends Service
}
/**
* 回复根成功消息
* 回复根成功消息.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 根状态码
@ -205,7 +206,7 @@ class InterfaceService extends Service
}
/**
* 回复根签名消息
* 回复根签名消息.
* @param mixed $info 消息内容
* @param mixed $data 返回数据
* @param mixed $code 根状态码
@ -224,8 +225,7 @@ class InterfaceService extends Service
* 接口数据模拟请求
* @param string $uri 接口地址
* @param array $data 请求数据
* @param boolean $check 验证结果
* @return array
* @param bool $check 验证结果
* @throws Exception
*/
public function doRequest(string $uri, array $data = [], bool $check = true): array
@ -237,21 +237,26 @@ class InterfaceService extends Service
throw new Exception(lang('接口请求响应格式异常!'));
}
// 返回业务异常结果
if (empty($result['code'])) throw new Exception($result['info']);
if (empty($result['code'])) {
throw new Exception($result['info']);
}
$array = is_array($result['data']) ? $result['data'] : json_decode($result['data'], true);
// 无需验证直接返回
if (empty($check)) return $array;
if (empty($check)) {
return $array;
}
// 返回结果签名验证
$json = is_string($result['data']) ? $result['data'] : json_encode($result['data'], JSON_UNESCAPED_UNICODE);
$build = $this->signString($json, $result['time'], $result['nostr']);
if ($build['sign'] === $result['sign']) return $array ?: [];
if ($build['sign'] === $result['sign']) {
return $array ?: [];
}
throw new Exception(lang('返回结果签名验证失败!'));
}
/**
* 接口响应数据签名
* 接口响应数据签名.
* @param array $data ['appid','nostr','time','sign','data']
* @return array
*/
private function signData(array $data): array
{
@ -259,11 +264,10 @@ class InterfaceService extends Service
}
/**
* 数据字符串数据签名
* 数据字符串数据签名.
* @param string $json 待签名的数据
* @param mixed $time 签名的时间戳
* @param mixed $rand 签名随机字符
* @return array
*/
private function signString(string $json, $time = null, $rand = null): array
{
@ -272,4 +276,4 @@ class InterfaceService extends Service
$sign = md5("{$this->appid}#{$json}#{$time}#{$this->appkey}#{$rand}");
return ['appid' => $this->appid, 'nostr' => $rand, 'time' => $time, 'sign' => $sign, 'data' => $json];
}
}
}

View File

@ -1,84 +1,89 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
use think\admin\extend\DataExtend;
use think\admin\model\SystemMenu;
use think\admin\Service;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 系统菜单管理服务
* @class MenuService
* @package app\admin\service
*/
class MenuService extends Service
{
/**
* 获取可选菜单节点.
* @param bool $force 强制刷新
*/
public static function getList(bool $force = false): array
{
$nodes = sysvar($keys = 'think.admin.menus') ?: [];
if (empty($force) && count($nodes) > 0) {
return $nodes;
} $nodes = [];
foreach (NodeService::getMethods($force) as $node => $method) {
if ($method['ismenu']) {
$nodes[] = ['node' => $node, 'title' => self::lang($method['title'])];
}
}
return sysvar($keys, $nodes);
}
/**
* 菜单分组语言包
* @param string $name
* @return string
* 获取系统菜单树数据.
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getTree(): array
{
$menus = SystemMenu::mk()->where(['status' => 1])->order('sort desc,id asc')->select()->toArray();
if (function_exists('admin_menu_filter')) {
$menus = call_user_func('admin_menu_filter', $menus);
}
foreach ($menus as &$menu) {
$menu['title'] = self::lang($menu['title']);
}
return static::filter(DataExtend::arr2tree($menus));
}
/**
* 菜单分组语言包.
*/
private static function lang(string $name): string
{
$lang = lang("menus_{$name}");
if (stripos($lang, 'menus_') === 0) {
return lang(substr($lang, 6));
} else {
return $lang;
}
return $lang;
}
/**
* 获取可选菜单节点
* @param boolean $force 强制刷新
* @return array
*/
public static function getList(bool $force = false): array
{
$nodes = sysvar($keys = 'think.admin.menus') ?: [];
if (empty($force) && count($nodes) > 0) return $nodes; else $nodes = [];
foreach (NodeService::getMethods($force) as $node => $method) {
if ($method['ismenu']) $nodes[] = ['node' => $node, 'title' => self::lang($method['title'])];
}
return sysvar($keys, $nodes);
}
/**
* 获取系统菜单树数据
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getTree(): array
{
$menus = SystemMenu::mk()->where(['status' => 1])->order('sort desc,id asc')->select()->toArray();
if (function_exists('admin_menu_filter')) $menus = call_user_func('admin_menu_filter', $menus);
foreach ($menus as &$menu) $menu['title'] = self::lang($menu['title']);
return static::filter(DataExtend::arr2tree($menus));
}
/**
* 后台主菜单权限过滤
* 后台主菜单权限过滤.
* @param array $menus 当前菜单列表
* @return array
*/
private static function filter(array $menus): array
{
@ -91,13 +96,17 @@ class MenuService extends Service
} elseif (empty($menu['url']) || $menu['url'] === '#' || !(empty($menu['node']) || AdminService::check($menu['node']))) {
unset($menus[$key]);
} elseif (preg_match('#^(https?:)?//\w+#i', $menu['url'])) {
if ($menu['params']) $menu['url'] .= (strpos($menu['url'], '?') === false ? '?' : '&') . $menu['params'];
if ($menu['params']) {
$menu['url'] .= (strpos($menu['url'], '?') === false ? '?' : '&') . $menu['params'];
}
} else {
$node = join('/', array_slice(str2arr($menu['url'], '/'), 0, 3));
$menu['url'] = admuri($menu['url']) . ($menu['params'] ? '?' . $menu['params'] : '');
if (!AdminService::check($node)) unset($menus[$key]);
if (!AdminService::check($node)) {
unset($menus[$key]);
}
}
}
return $menus;
}
}
}

View File

@ -1,30 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
use think\admin\Exception;
use think\admin\extend\HttpExtend;
use think\admin\Service;
/**
* 旧助通短信接口服务
* @class MessageService
* @package app\store\service
* @deprecated 建议使用云平台服务
* =================================
*
@ -55,28 +57,31 @@ use think\admin\Service;
*/
class MessageService extends Service
{
private $table;
private $chinaUsername;
private $chinaPassword;
private $globeUsername;
private $globePassword;
/**
* @return $this
* @throws \think\admin\Exception
* 错误消息处理.
* @var array
*/
protected function initialize(): MessageService
{
$this->table = 'SystemMessageHistory';
$this->chinaUsername = sysconf('sms_zt.china_username|raw');
$this->chinaPassword = sysconf('sms_zt.china_password|raw');
$this->globeUsername = sysconf('sms_zt.globe_username|raw');
$this->globePassword = sysconf('sms_zt.globe_password|raw');
return $this;
}
private $globeMessageMap = [
2 => '用户账号为空',
3 => '用户账号错误',
4 => '授权密码为空',
5 => '授权密码错误',
6 => '当前时间为空',
7 => '当前时间错误',
8 => '用户类型错误',
9 => '用户鉴权错误',
10 => '请求IP已被列入黑名单',
];
/**
* 配置内陆短信认证
@ -105,8 +110,7 @@ class MessageService extends Service
}
/**
* 设置存储数据表
* @param string $table
* 设置存储数据表.
* @return $this
*/
public function setSaveTable(string $table): MessageService
@ -116,10 +120,7 @@ class MessageService extends Service
}
/**
* 生成短信内容
* @param string $content
* @param array $params
* @return string
* 生成短信内容.
*/
public function buildContent(string $content, array $params = []): string
{
@ -131,25 +132,24 @@ class MessageService extends Service
/**
* 发送国内短信验证码
* @param integer|string $phone 手机号
* @param integer|string $content 短信内容
* @param integer|string $productid 短信通道
* @return boolean
* @param int|string $phone 手机号
* @param int|string $content 短信内容
* @param int|string $productid 短信通道
*/
public function sendChinaSms($phone, $content, $productid = '676767'): bool
{
$tkey = date("YmdHis");
$result = HttpExtend::get('http' . '://www.ztsms.cn/sendNSms.do', [
'tkey' => $tkey,
'mobile' => $phone,
'content' => $content,
'username' => $this->chinaUsername,
$tkey = date('YmdHis');
$result = HttpExtend::get('http://www.ztsms.cn/sendNSms.do', [
'tkey' => $tkey,
'mobile' => $phone,
'content' => $content,
'username' => $this->chinaUsername,
'productid' => $productid,
'password' => md5(md5($this->chinaPassword) . $tkey),
'password' => md5(md5($this->chinaPassword) . $tkey),
]);
[$code] = explode(',', $result . ',');
$this->app->db->name($this->table)->insert([
'phone' => $phone, 'region' => '860',
'phone' => $phone, 'region' => '860',
'content' => $content, 'result' => $result,
]);
return intval($code) === 1;
@ -157,11 +157,10 @@ class MessageService extends Service
/**
* 发送国内短信验证码
* @param integer|string $phone 目标手机
* @param integer $wait 等待时间
* @param int|string $phone 目标手机
* @param int $wait 等待时间
* @param string $type 短信模板
* @return array
* @throws \think\admin\Exception
* @throws Exception
*/
public function sendChinaSmsByCode($phone, int $wait = 120, string $type = 'sms_reg_template'): array
{
@ -178,17 +177,15 @@ class MessageService extends Service
if ($this->sendChinaSms($phone, str_replace('{code}', $code, $content))) {
$dtime = ($cache['time'] + $wait < time()) ? 0 : ($wait - time() + $cache['time']);
return [1, lang('短信验证码发送成功!'), ['time' => $dtime]];
} else {
return [0, lang('短信发送失败,请稍候再试!'), []];
}
return [0, lang('短信发送失败,请稍候再试!'), []];
}
/**
* 验证手机短信验证码
* @param integer|string $phone 目标手机
* @param integer|string $code 短信验证码
* @param int|string $phone 目标手机
* @param int|string $code 短信验证码
* @param string $type 短信模板
* @return boolean
*/
public function check($phone, $code, string $type = 'sms_reg_template'): bool
{
@ -197,59 +194,43 @@ class MessageService extends Service
}
/**
* 查询国内短信余额
* @return array
* 查询国内短信余额.
*/
public function queryChinaSmsBalance(): array
{
$tkey = date("YmdHis");
$result = HttpExtend::get('http' . '://www.ztsms.cn/balanceN.do', [
$tkey = date('YmdHis');
$result = HttpExtend::get('http://www.ztsms.cn/balanceN.do', [
'username' => $this->chinaUsername, 'tkey' => $tkey,
'password' => md5(md5($this->chinaPassword) . $tkey),
]);
if ($result > -1) {
return ['code' => 1, 'num' => $result, 'msg' => lang('获取短信剩余条数成功!')];
} elseif ($result > -2) {
return ['code' => 0, 'num' => '0', 'msg' => lang('用户名或者密码不正确!')];
} elseif ($result > -3) {
return ['code' => 0, 'num' => '0', 'msg' => lang('tkey不正确')];
} elseif ($result > -4) {
return ['code' => 0, 'num' => '0', 'msg' => lang('用户不存在或用户停用!')];
} else {
return ['code' => 0, 'num' => '0', 'msg' => lang('未知错误原因!')];
}
if ($result > -2) {
return ['code' => 0, 'num' => '0', 'msg' => lang('用户名或者密码不正确!')];
}
if ($result > -3) {
return ['code' => 0, 'num' => '0', 'msg' => lang('tkey不正确')];
}
if ($result > -4) {
return ['code' => 0, 'num' => '0', 'msg' => lang('用户不存在或用户停用!')];
}
return ['code' => 0, 'num' => '0', 'msg' => lang('未知错误原因!')];
}
/**
* 错误消息处理
* @var array
*/
private $globeMessageMap = [
2 => '用户账号为空',
3 => '用户账号错误',
4 => '授权密码为空',
5 => '授权密码错误',
6 => '当前时间为空',
7 => '当前时间错误',
8 => '用户类型错误',
9 => '用户鉴权错误',
10 => '请求IP已被列入黑名单',
];
/**
* 发送国际短信内容
* @param integer|string $code 国家代码
* @param integer|string $mobile 手机号码
* 发送国际短信内容.
* @param int|string $code 国家代码
* @param int|string $mobile 手机号码
* @param string $content 发送内容
* @return boolean
* @throws \think\admin\Exception
* @throws Exception
*/
public function sendGlobeSms($code, $mobile, string $content): bool
{
$tkey = date("YmdHis");
$result = HttpExtend::get('http' . '://intl.zthysms.com/intSendSms.do', [
'tkey' => $tkey, 'code' => $code, 'mobile' => $mobile,
'content' => $content, 'username' => sysconf('sms_zt_username2|raw'),
$tkey = date('YmdHis');
$result = HttpExtend::get('http://intl.zthysms.com/intSendSms.do', [
'tkey' => $tkey, 'code' => $code, 'mobile' => $mobile,
'content' => $content, 'username' => sysconf('sms_zt_username2|raw'),
'password' => md5(md5(sysconf('sms_zt_password2|raw')) . $tkey),
]);
$this->app->db->name($this->table)->insert([
@ -259,25 +240,22 @@ class MessageService extends Service
}
/**
* 查询国际短信余额
* @return array
* 查询国际短信余额.
*/
public function queryGlobeSmsBalance(): array
{
$tkey = date("YmdHis");
$result = HttpExtend::get('http' . '://intl.zthysms.com/intBalance.do', [
$tkey = date('YmdHis');
$result = HttpExtend::get('http://intl.zthysms.com/intBalance.do', [
'username' => $this->globeUsername, 'tkey' => $tkey, 'password' => md5(md5($this->globePassword) . $tkey),
]);
if (!is_numeric($result) && ($state = intval($result)) && isset($this->globeMessageMap[$state])) {
return ['code' => 0, 'num' => 0, 'msg' => lang($this->globeMessageMap[$state])];
} else {
return ['code' => 1, 'num' => $result, 'msg' => lang('查询成功')];
}
return ['code' => 1, 'num' => $result, 'msg' => lang('查询成功')];
}
/**
* 获取国际地域编号
* @return array
* 获取国际地域编号.
*/
public function getGlobeRegionMap(): array
{
@ -502,4 +480,18 @@ class MessageService extends Service
['title' => '黑山共和国', 'english' => 'The Republic of Montenegro', 'code' => 382],
];
}
/**
* @return $this
* @throws Exception
*/
protected function initialize(): MessageService
{
$this->table = 'SystemMessageHistory';
$this->chinaUsername = sysconf('sms_zt.china_username|raw');
$this->chinaPassword = sysconf('sms_zt.china_password|raw');
$this->globeUsername = sysconf('sms_zt.globe_username|raw');
$this->globePassword = sysconf('sms_zt.globe_password|raw');
return $this;
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -22,15 +24,13 @@ use think\admin\Library;
use think\admin\Service;
/**
* 系统模块管理
* 系统模块管理.
* @class ModuleService
* @package think\admin\service
*/
class ModuleService extends Service
{
/**
* 获取版本号信息
* @return string
* 获取版本号信息.
*/
public static function getVersion(): string
{
@ -39,55 +39,55 @@ class ModuleService extends Service
}
/**
* 获取运行参数变量
* 获取运行参数变量.
* @param string $field 指定字段
* @return string
*/
public static function getRunVar(string $field): string
{
$file = syspath('vendor/binarys.php');
if (is_file($file) && is_array($binarys = include $file)) {
return $binarys[$field] ?? '';
} else {
return '';
}
return '';
}
/**
* 获取 PHP 执行路径
* @return string
* 获取 PHP 执行路径.
*/
public static function getPhpExec(): string
{
if ($phpExec = sysvar($keys = 'phpBinary')) return $phpExec;
if ($phpExec = sysvar($keys = 'phpBinary')) {
return $phpExec;
}
if (ProcessService::isFile($phpExec = self::getRunVar('php'))) {
return sysvar($keys, $phpExec);
} else {
$phpExec = str_replace('/sbin/php-fpm', '/bin/php', PHP_BINARY);
$phpExec = preg_replace('#-(cgi|fpm)(\.exe)?$#', '$2', $phpExec);
return sysvar($keys, ProcessService::isFile($phpExec) ? $phpExec : 'php');
}
$phpExec = str_replace('/sbin/php-fpm', '/bin/php', PHP_BINARY);
$phpExec = preg_replace('#-(cgi|fpm)(\.exe)?$#', '$2', $phpExec);
return sysvar($keys, ProcessService::isFile($phpExec) ? $phpExec : 'php');
}
/**
* 获取应用模块
* @param array $data
* @return array
* 获取应用模块.
*/
public static function getModules(array $data = []): array
{
$path = Library::$sapp->getBasePath();
foreach (scandir($path) as $item) if ($item[0] !== '.') {
if (is_dir($path . $item)) $data[] = $item;
foreach (scandir($path) as $item) {
if ($item[0] !== '.') {
if (is_dir($path . $item)) {
$data[] = $item;
}
}
}
return $data;
}
/**
* 获取本地组件
* 获取本地组件.
* @param ?string $package 指定包名
* @param boolean $force 强制刷新
* @return array|string|null
* @param bool $force 强制刷新
* @return null|array|string
*/
public static function getLibrarys(?string $package = null, bool $force = false)
{
@ -97,4 +97,4 @@ class ModuleService extends Service
}
return empty($package) ? $plugs : ($plugs[$package] ?? null);
}
}
}

View File

@ -1,25 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
use ReflectionClass;
use ReflectionMethod;
use think\admin\Exception;
use think\admin\extend\ToolsExtend;
use think\admin\Library;
@ -27,54 +27,78 @@ use think\admin\Plugin;
use think\admin\Service;
/**
* 应用节点服务管理
* 应用节点服务管理.
* @class NodeService
* @method static array getModules() 获取应用列表
* @method static array scanDirectory() 扫描目录列表
* @package think\admin\service
*/
class NodeService extends Service
{
/**
* 重构兼容处理.
* @return array
* @throws Exception
*/
public function __call(string $name, array $arguments)
{
return static::__callStatic($name, $arguments);
}
/**
* 获取默认应用空间名
* 重构兼容处理.
* @return array
* @throws Exception
*/
public static function __callStatic(string $name, array $arguments)
{
if ($name === 'scanDirectory') {
return ToolsExtend::scan(...$arguments);
}
if ($name === 'getModules') {
return ModuleService::getModules(...$arguments);
}
throw new Exception("method not exists: NodeService::{$name}()");
}
/**
* 获取默认应用空间名.
* @param string $suffix 后缀路径
* @return string
*/
public static function space(string $suffix = ''): string
{
$default = Library::$sapp->config->get('app.app_namespace') ?: 'app';
return empty($suffix) ? $default : trim($default . '\\' . trim($suffix, '\\/'), '\\');
return empty($suffix) ? $default : trim($default . '\\' . trim($suffix, '\/'), '\\');
}
/**
* 驼峰转下划线规则
* @param string $name
* @return string
* 驼峰转下划线规则.
*/
public static function nameTolower(string $name): string
{
$dots = [];
foreach (explode('.', strtr($name, '/', '.')) as $dot) {
$dots[] = trim(preg_replace("/[A-Z]/", "_\\0", $dot), '_');
$dots[] = trim(preg_replace('/[A-Z]/', '_\0', $dot), '_');
}
return strtolower(join('.', $dots));
}
/**
* 获取当前节点内容
* 获取当前节点内容.
* @param string $type app|module|controller|action
* @return string
*/
public static function getCurrent(string $type = ''): string
{
// 获取应用节点
$appname = strtolower(Library::$sapp->http->getName());
if (in_array($type, ['app', 'module'])) return $appname;
if (in_array($type, ['app', 'module'])) {
return $appname;
}
// 获取控制器节点
$controller = static::nameTolower(Library::$sapp->request->controller());
if ($type === 'controller') return "{$appname}/{$controller}";
if ($type === 'controller') {
return "{$appname}/{$controller}";
}
// 获取方法权限节点
$method = strtolower(Library::$sapp->request->action());
@ -82,13 +106,13 @@ class NodeService extends Service
}
/**
* 检查并完整节点内容
* @param ?string $node
* @return string
* 检查并完整节点内容.
*/
public static function fullNode(?string $node = ''): string
{
if (empty($node)) return static::getCurrent();
if (empty($node)) {
return static::getCurrent();
}
switch (count($attrs = explode('/', $node))) {
case 1: # 方法名
return static::getCurrent('controller') . '/' . strtolower($node);
@ -102,16 +126,17 @@ class NodeService extends Service
}
/**
* 获取所有控制器入口
* @param boolean $force 强制更新
* @return array
* 获取所有控制器入口.
* @param bool $force 强制更新
*/
public static function getMethods(bool $force = false): array
{
$skey = 'think.admin.methods';
if (empty($force)) {
$data = sysvar($skey) ?: Library::$sapp->cache->get('SystemAuthNode', []);
if (count($data) > 0) return sysvar($skey, $data);
if (count($data) > 0) {
return sysvar($skey, $data);
}
} else {
$data = [];
}
@ -120,18 +145,22 @@ class NodeService extends Service
$ignoreAppNames = Library::$sapp->config->get('app.rbac_ignore', []);
// 扫描所有代码控制器节点,更新节点缓存
foreach (ToolsExtend::scan(Library::$sapp->getBasePath(), null, 'php') as $name) {
if (preg_match("|^(\w+)/controller/(.+)\.php$|i", strtr($name, '\\', '/'), $matches)) {
if (preg_match('|^(\w+)/controller/(.+)\.php$|i', strtr($name, '\\', '/'), $matches)) {
[, $appName, $className] = $matches;
if (in_array($appName, $ignoreAppNames)) continue;
if (in_array($appName, $ignoreAppNames)) {
continue;
}
static::_parseClass($appName, self::space($appName), $className, $ignoreMethods, $data);
}
}
// 扫描所有插件代码
foreach (Plugin::get() as $appName => $plugin) {
if (in_array($appName, $ignoreAppNames)) continue;
if (in_array($appName, $ignoreAppNames)) {
continue;
}
[$appPath, $appSpace] = [$plugin['path'], $plugin['space']];
foreach (ToolsExtend::scan($appPath, null, 'php') as $name) {
if (preg_match("|^.*?controller/(.+)\.php$|i", strtr($name, '\\', '/'), $matches)) {
if (preg_match('|^.*?controller/(.+)\.php$|i', strtr($name, '\\', '/'), $matches)) {
static::_parseClass($appName, $appSpace, $matches[1], $ignoreMethods, $data);
}
}
@ -146,73 +175,45 @@ class NodeService extends Service
}
/**
* 解析节点数据
* 解析节点数据.
* @param string $appName 应用名称
* @param string $appSpace 应用空间
* @param string $className 应用类型
* @param array $ignoreNode 忽略节点
* @param array $data 绑定节点的数据
* @return void
*/
private static function _parseClass(string $appName, string $appSpace, string $className, array $ignoreNode, array &$data)
{
$classfull = strtr("{$appSpace}/controller/{$className}", '/', '\\');
if (class_exists($classfull) && ($class = new ReflectionClass($classfull))) {
if (class_exists($classfull) && ($class = new \ReflectionClass($classfull))) {
$prefix = strtolower(strtr("{$appName}/" . static::nameTolower($className), '\\', '/'));
$data[$prefix] = static::_parseComment($class->getDocComment() ?: '', $className);
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
if (in_array($metname = $method->getName(), $ignoreNode)) continue;
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if (in_array($metname = $method->getName(), $ignoreNode)) {
continue;
}
$data[strtolower("{$prefix}/{$metname}")] = static::_parseComment($method->getDocComment() ?: '', $metname);
}
}
}
/**
* 解析硬节点属性
* 解析硬节点属性.
* @param string $comment 备注内容
* @param string $default 默认标题
* @return array
*/
private static function _parseComment(string $comment, string $default = ''): array
{
$text = strtr($comment, "\n", ' ');
$title = preg_replace('/^\/\*\s*\*\s*\*\s*(.*?)\s*\*.*?$/', '$1', $text);
if (in_array(substr($title, 0, 5), ['@auth', '@menu', '@logi'])) $title = $default;
if (in_array(substr($title, 0, 5), ['@auth', '@menu', '@logi'])) {
$title = $default;
}
return [
'title' => $title ?: $default,
'isauth' => intval(preg_match('/@auth\s*true/i', $text)),
'ismenu' => intval(preg_match('/@menu\s*true/i', $text)),
'title' => $title ?: $default,
'isauth' => intval(preg_match('/@auth\s*true/i', $text)),
'ismenu' => intval(preg_match('/@menu\s*true/i', $text)),
'islogin' => intval(preg_match('/@login\s*true/i', $text)),
];
}
/**
* 重构兼容处理
* @param string $name
* @param array $arguments
* @return array
* @throws \think\admin\Exception
*/
public function __call(string $name, array $arguments)
{
return static::__callStatic($name, $arguments);
}
/**
* 重构兼容处理
* @param string $name
* @param array $arguments
* @return array
* @throws \think\admin\Exception
*/
public static function __callStatic(string $name, array $arguments)
{
if ($name === 'scanDirectory') {
return ToolsExtend::scan(...$arguments);
} elseif ($name === 'getModules') {
return ModuleService::getModules(...$arguments);
} else {
throw new Exception("method not exists: NodeService::{$name}()");
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -27,15 +29,24 @@ use think\admin\Service;
/**
* 系统进程管理服务
* @class ProcessService
* @package think\admin\service
*/
class ProcessService extends Service
{
/**
* 静态兼容处理.
* @return array
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if ($method === 'thinkCreate') {
return self::thinkExec(...$arguments);
}
throw new Exception("method not exists: ProcessService::{$method}()");
}
/**
* 生成 PHP 指令
* @param string $args
* @return string
* 生成 PHP 指令.
*/
public static function php(string $args = ''): string
{
@ -43,10 +54,9 @@ class ProcessService extends Service
}
/**
* 生成 Think 指令
* 生成 Think 指令.
* @param string $args 指令参数
* @param boolean $simple 仅返回内容
* @return string
* @param bool $simple 仅返回内容
*/
public static function think(string $args = '', bool $simple = false): string
{
@ -55,9 +65,8 @@ class ProcessService extends Service
}
/**
* 生成 Composer 指令
* 生成 Composer 指令.
* @param string $args 参数
* @return string
*/
public static function composer(string $args = ''): string
{
@ -71,11 +80,10 @@ class ProcessService extends Service
}
/**
* 创建 Think 进程
* 创建 Think 进程.
* @param string $args 执行参数
* @param integer $usleep 延时等待
* @param boolean $doQuery 查询进程
* @return array
* @param int $usleep 延时等待
* @param bool $doQuery 查询进程
*/
public static function thinkExec(string $args, int $usleep = 0, bool $doQuery = false): array
{
@ -84,9 +92,8 @@ class ProcessService extends Service
}
/**
* 检查 Think 进程
* 检查 Think 进程.
* @param string $args 执行参数
* @return array
*/
public static function thinkQuery(string $args): array
{
@ -94,9 +101,9 @@ class ProcessService extends Service
}
/**
* 创建异步进程
* 创建异步进程.
* @param string $command 任务指令
* @param integer $usleep 延时毫米
* @param int $usleep 延时毫米
*/
public static function create(string $command, int $usleep = 0)
{
@ -109,35 +116,37 @@ class ProcessService extends Service
}
/**
* 查询进程列表
* 查询进程列表.
* @param string $cmd 任务指令
* @param string $name 进程名称
* @return array
*/
public static function query(string $cmd, string $name = 'php.exe'): array
{
$list = [];
if (static::isWin()) {
$lines = static::exec("wmic process where name=\"{$name}\" get processid,CommandLine", true);
foreach ($lines as $line) if (is_numeric(stripos($line, $cmd))) {
$attr = explode(' ', trim(preg_replace('#\s+#', ' ', $line)));
$list[] = ['pid' => array_pop($attr), 'cmd' => join(' ', $attr)];
foreach ($lines as $line) {
if (is_numeric(stripos($line, $cmd))) {
$attr = explode(' ', trim(preg_replace('#\s+#', ' ', $line)));
$list[] = ['pid' => array_pop($attr), 'cmd' => join(' ', $attr)];
}
}
} else {
$lines = static::exec("ps ax|grep -v grep|grep \"{$cmd}\"", true);
foreach ($lines as $line) if (is_numeric(stripos($line, $cmd))) {
$attr = explode(' ', trim(preg_replace('#\s+#', ' ', $line)));
[$pid] = [array_shift($attr), array_shift($attr), array_shift($attr), array_shift($attr)];
$list[] = ['pid' => $pid, 'cmd' => join(' ', $attr)];
foreach ($lines as $line) {
if (is_numeric(stripos($line, $cmd))) {
$attr = explode(' ', trim(preg_replace('#\s+#', ' ', $line)));
[$pid] = [array_shift($attr), array_shift($attr), array_shift($attr), array_shift($attr)];
$list[] = ['pid' => $pid, 'cmd' => join(' ', $attr)];
}
}
}
return $list;
}
/**
* 关闭指定进程
* @param integer $pid 进程号
* @return boolean
* 关闭指定进程.
* @param int $pid 进程号
*/
public static function close(int $pid): bool
{
@ -150,11 +159,11 @@ class ProcessService extends Service
}
/**
* 立即执行指令
* 立即执行指令.
* @param string $command 执行指令
* @param boolean $outarr 返回数组
* @param bool $outarr 返回数组
* @param ?callable $callable 逐行处理
* @return string|array
* @return array|string
*/
public static function exec(string $command, bool $outarr = false, ?callable $callable = null)
{
@ -167,20 +176,20 @@ class ProcessService extends Service
}
/**
* 输出命令行消息
* 输出命令行消息.
* @param string $message 输出内容
* @param integer $backline 回退行数
* @return void
* @param int $backline 回退行数
*/
public static function message(string $message, int $backline = 0)
{
while ($backline-- > 0) $message = "\033[1A\r\033[K{$message}";
while ($backline-- > 0) {
$message = "\033[1A\r\033[K{$message}";
}
print_r($message . PHP_EOL);
}
/**
* 判断系统类型 WINDOWS
* @return boolean
* 判断系统类型 WINDOWS.
*/
public static function isWin(): bool
{
@ -188,8 +197,7 @@ class ProcessService extends Service
}
/**
* 判断系统类型 UNIX
* @return bool
* 判断系统类型 UNIX.
*/
public static function isUnix(): bool
{
@ -197,9 +205,8 @@ class ProcessService extends Service
}
/**
* 检查文件是否存在
* 检查文件是否存在.
* @param string $file 文件路径
* @return boolean
*/
public static function isFile(string $file): bool
{
@ -209,28 +216,11 @@ class ProcessService extends Service
try {
if (self::isWin()) {
return self::exec("if exist \"{$file}\" echo 1") === '1';
} else {
return self::exec("if [ -f \"{$file}\" ];then echo 1;fi") === '1';
}
return self::exec("if [ -f \"{$file}\" ];then echo 1;fi") === '1';
} catch (\Error|\Exception $exception) {
return false;
}
}
}
/**
* 静态兼容处理
* @param string $method
* @param array $arguments
* @return array
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if ($method === 'thinkCreate') {
return self::thinkExec(...$arguments);
} else {
throw new Exception("method not exists: ProcessService::{$method}()");
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -26,58 +28,55 @@ use think\admin\Service;
/**
* 任务基础服务
* @class QueueService
* @package think\admin\service
*/
class QueueService extends Service
{
/**
* 当前任务编号
* 当前任务编号.
* @var string
*/
public $code = '';
/**
* 当前任务标题
* 当前任务标题.
* @var string
*/
public $title = '';
/**
* 当前任务参数
* 当前任务参数.
* @var array
*/
public $data = [];
/**
* 当前任务数据
* 当前任务数据.
* @var SystemQueue
*/
public $record;
/**
* 运行消息记录
* 运行消息记录.
* @var array
*/
private $msgs = [];
/**
* 运行消息写库
* @var boolean
* 运行消息写库.
* @var bool
*/
private $msgsWriteDb = false;
/**
* 异常尝试次数
* @var integer
* 异常尝试次数.
* @var int
*/
private $tryTimes = 0;
/**
* 数据初始化
* @param string $code
* 数据初始化.
* @return static
* @throws \think\admin\Exception
* @throws Exception
*/
public function initialize(string $code = ''): QueueService
{
@ -90,7 +89,7 @@ class QueueService extends Service
if (!empty($code)) {
$this->record = SystemQueue::mk()->master()->where(['code' => $code])->findOrEmpty();
if ($this->record->isEmpty()) {
$message = sprintf("Qeueu initialize failed, Queue %s not found.", $code);
$message = sprintf('Qeueu initialize failed, Queue %s not found.', $code);
$this->app->log->error($message);
throw new Exception($message);
}
@ -105,9 +104,9 @@ class QueueService extends Service
/**
* 重发异步任务
* @param integer $wait 等待时间
* @param int $wait 等待时间
* @return $this
* @throws \think\admin\Exception
* @throws Exception
*/
public function reset(int $wait = 0): QueueService
{
@ -122,25 +121,25 @@ class QueueService extends Service
/**
* 添加定时清理任务
* @param integer $loops 循环时间
* @param int $loops 循环时间
* @return $this
* @throws \think\admin\Exception
* @throws Exception
*/
public static function addCleanQueue(int $loops = 3600): QueueService
{
return static::register('定时清理系统任务数据', "xadmin:service clean", 0, [], 0, $loops);
return static::register('定时清理系统任务数据', 'xadmin:service clean', 0, [], 0, $loops);
}
/**
* 注册异步处理任务
* @param string $title 任务名称
* @param string $command 执行脚本
* @param integer $later 延时时间
* @param int $later 延时时间
* @param array $data 任务附加数据
* @param integer $rscript 任务类型(0单例,1多例)
* @param integer $loops 循环等待时间
* @param int $rscript 任务类型(0单例,1多例)
* @param int $loops 循环等待时间
* @return $this
* @throws \think\admin\Exception
* @throws Exception
*/
public static function register(string $title, string $command, int $later = 0, array $data = [], int $rscript = 0, int $loops = 0): QueueService
{
@ -150,21 +149,22 @@ class QueueService extends Service
throw new Exception(lang('已创建请等待处理完成!'), 0, $queue['code']);
}
// 生成唯一编号
do $map = ['code' => $code = CodeExtend::uniqidDate(16, 'Q')];
while (($queue = SystemQueue::mk()->master()->where($map)->findOrEmpty())->isExists());
do {
$map = ['code' => $code = CodeExtend::uniqidDate(16, 'Q')];
} while (($queue = SystemQueue::mk()->master()->where($map)->findOrEmpty())->isExists());
// 写入任务数据
$queue->save([
'code' => $code,
'title' => $title,
'command' => $command,
'attempts' => 0,
'rscript' => intval(boolval($rscript)),
'exec_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
'exec_time' => $later > 0 ? time() + $later : time(),
'code' => $code,
'title' => $title,
'command' => $command,
'attempts' => 0,
'rscript' => intval(boolval($rscript)),
'exec_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
'exec_time' => $later > 0 ? time() + $later : time(),
'enter_time' => 0,
'outer_time' => 0,
'loops_time' => $loops,
'create_at' => date('Y-m-d H:i:s'),
'create_at' => date('Y-m-d H:i:s'),
]);
$that = static::instance([], true)->initialize($code);
$that->progress(1, '>>> 任务创建成功 <<<', '0.00');
@ -177,36 +177,53 @@ class QueueService extends Service
}
/**
* 设置任务进度信息
* @param ?integer $status 任务状态
* 设置任务进度信息.
* @param ?int $status 任务状态
* @param ?string $message 进度消息
* @param ?string $progress 进度数值
* @param integer $backline 回退信息行
* @return array
* @throws \think\admin\Exception
* @param int $backline 回退信息行
* @throws Exception
*/
public function progress(?int $status = null, ?string $message = null, ?string $progress = null, int $backline = 0): array
{
if (is_numeric($status) && intval($status) === 3) {
if (!is_numeric($progress)) $progress = '100.00';
if (is_null($message)) $message = '>>> 任务已经完成 <<<';
if (!is_numeric($progress)) {
$progress = '100.00';
}
if (is_null($message)) {
$message = '>>> 任务已经完成 <<<';
}
}
if (is_numeric($status) && intval($status) === 4) {
if (!is_numeric($progress)) $progress = '0.00';
if (is_null($message)) $message = '>>> 任务执行失败 <<<';
if (!is_numeric($progress)) {
$progress = '0.00';
}
if (is_null($message)) {
$message = '>>> 任务执行失败 <<<';
}
}
try {
if (empty($this->msgs)) $this->msgs = $this->app->cache->get("queue_{$this->code}_progress", [
'code' => $this->code, 'status' => $status, 'sctime' => 0, 'message' => $message, 'progress' => $progress, 'history' => []
]);
if (empty($this->msgs)) {
$this->msgs = $this->app->cache->get("queue_{$this->code}_progress", [
'code' => $this->code, 'status' => $status, 'sctime' => 0, 'message' => $message, 'progress' => $progress, 'history' => [],
]);
}
$this->tryTimes = 0;
} catch (\Exception|\Error $exception) {
if ($this->tryTimes++ > 10) throw new Exception('读取进程缓存异常!');
} catch (\Error|\Exception $exception) {
if ($this->tryTimes++ > 10) {
throw new Exception('读取进程缓存异常!');
}
return $this->progress($status, $message, $progress, $backline);
}
while (--$backline > -1 && count($this->msgs['history']) > 0) array_pop($this->msgs['history']);
if (is_numeric($status)) $this->msgs['status'] = intval($status);
if (is_numeric($progress)) $progress = str_pad(sprintf('%.2f', $progress), 6, '0', STR_PAD_LEFT);
while (--$backline > -1 && count($this->msgs['history']) > 0) {
array_pop($this->msgs['history']);
}
if (is_numeric($status)) {
$this->msgs['status'] = intval($status);
}
if (is_numeric($progress)) {
$progress = str_pad(sprintf('%.2f', $progress), 6, '0', STR_PAD_LEFT);
}
if (is_string($message) && is_null($progress)) {
$this->msgs['swrite'] = 0;
$this->msgs['message'] = $message;
@ -221,48 +238,28 @@ class QueueService extends Service
$this->msgs['progress'] = $progress;
$this->msgs['history'][] = ['message' => $message, 'progress' => $progress, 'datetime' => date('Y-m-d H:i:s')];
}
if (is_string($message) || is_numeric($progress)) if (count($this->msgs['history']) > 10) {
$this->msgs['history'] = array_slice($this->msgs['history'], -10);
if (is_string($message) || is_numeric($progress)) {
if (count($this->msgs['history']) > 10) {
$this->msgs['history'] = array_slice($this->msgs['history'], -10);
}
}
// 延时写入并返回内容
return $this->_lazyWrite();
}
/**
* 延时写入记录
* @param boolean $force 强制更新
* @return array
*/
private function _lazyWrite(bool $force = false): array
{
// 无消息状态
if (!isset($this->msgs['status'])) return $this->msgs;
// 消息延时写数据库
if ($force || empty($this->msgs['sctime']) || in_array($this->msgs['status'], [3, 4]) || microtime(true) - $this->msgs['sctime'] > 1) {
if (empty($this->msgs['swrite']) && $this->record->isExists()) {
[$this->msgs['swrite'], $this->msgs['sctime']] = [1, microtime(true)];
$this->app->cache->set("queue_{$this->code}_progress", $this->msgs, 864000);
if ($this->msgsWriteDb) {
$this->record->save(['message' => json_encode($this->msgs, JSON_UNESCAPED_UNICODE)]);
}
}
}
return $this->msgs;
}
/**
* 更新任务进度
* @param integer $total 记录总和
* @param integer $count 当前记录
* 更新任务进度.
* @param int $total 记录总和
* @param int $count 当前记录
* @param string $message 文字描述
* @param integer $backline 回退行数
* @throws \think\admin\Exception
* @param int $backline 回退行数
* @throws Exception
*/
public function message(int $total, int $count, string $message = '', int $backline = 0): void
{
$prefix = str_pad("{$count}", strlen(strval($total)), '0', STR_PAD_LEFT);
if (defined('WorkQueueCode')) {
$this->progress(2, "[{$prefix}/{$total}] {$message}", sprintf("%.2f", $count / max($total, 1) * 100), $backline);
$this->progress(2, "[{$prefix}/{$total}] {$message}", sprintf('%.2f', $count / max($total, 1) * 100), $backline);
} else {
ProcessService::message("[{$prefix}/{$total}] {$message}", $backline);
}
@ -279,7 +276,7 @@ class QueueService extends Service
}
/**
* 任务执行失败
* 任务执行失败.
* @param string $message 消息内容
* @throws Exception
*/
@ -289,11 +286,31 @@ class QueueService extends Service
}
/**
* 执行任务处理
* 执行任务处理.
* @param array $data 任务参数
* @return void
*/
public function execute(array $data = [])
public function execute(array $data = []) {}
/**
* 延时写入记录.
* @param bool $force 强制更新
*/
private function _lazyWrite(bool $force = false): array
{
// 无消息状态
if (!isset($this->msgs['status'])) {
return $this->msgs;
}
// 消息延时写数据库
if ($force || empty($this->msgs['sctime']) || in_array($this->msgs['status'], [3, 4]) || microtime(true) - $this->msgs['sctime'] > 1) {
if (empty($this->msgs['swrite']) && $this->record->isExists()) {
[$this->msgs['swrite'], $this->msgs['sctime']] = [1, microtime(true)];
$this->app->cache->set("queue_{$this->code}_progress", $this->msgs, 864000);
if ($this->msgsWriteDb) {
$this->record->save(['message' => json_encode($this->msgs, JSON_UNESCAPED_UNICODE)]);
}
}
}
return $this->msgs;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -29,31 +31,29 @@ use think\Response;
/**
* 系统运行服务
* @class RuntimeService
* @package think\admin\service
*/
class RuntimeService
{
/**
* 开发运行模式
* 开发运行模式.
* @var string
*/
public const MODE_DEVE = 'dev';
/**
* 演示运行模式
* 演示运行模式.
* @var string
*/
public const MODE_DEMO = 'demo';
/**
* 本地运行模式
* 本地运行模式.
* @var string
*/
public const MODE_LOCAL = 'local';
/**
* 环境配置文件位置
* 环境配置文件位置.
* @var string
*/
private static $envFile = './runtime/.env';
@ -65,9 +65,7 @@ class RuntimeService
private static $evnHash = '';
/**
* 系统服务初始化
* @param ?\think\App $app
* @return App
* 系统服务初始化.
*/
public static function init(?App $app = null): App
{
@ -81,7 +79,7 @@ class RuntimeService
}
/**
* 获取动态配置
* 获取动态配置.
* @param null|string $name 配置名称
* @param array $default 配置内容
* @return array|string
@ -103,11 +101,11 @@ class RuntimeService
}
/**
* 设置动态配置
* 设置动态配置.
* @param null|mixed $mode 支持模式
* @param null|array $appmap 应用映射
* @param null|array $domain 域名映射
* @return boolean 是否调试模式
* @return bool 是否调试模式
*/
public static function set(?string $mode = null, ?array $appmap = [], ?array $domain = []): bool
{
@ -118,8 +116,12 @@ class RuntimeService
// 组装配置文件格式
$rows[] = "mode = {$envs['mode']}";
foreach ($envs['appmap'] as $key => $item) $rows[] = "appmap[{$key}] = {$item}";
foreach ($envs['domain'] as $key => $item) $rows[] = "domain[{$key}] = {$item}";
foreach ($envs['appmap'] as $key => $item) {
$rows[] = "appmap[{$key}] = {$item}";
}
foreach ($envs['domain'] as $key => $item) {
$rows[] = "domain[{$key}] = {$item}";
}
// 写入并刷新文件希值
@file_put_contents(self::$envFile, "[RUNTIME]\n" . join("\n", $rows));
@ -132,8 +134,7 @@ class RuntimeService
}
/**
* 同步运行配置
* @return void
* 同步运行配置.
*/
public static function sync()
{
@ -142,9 +143,9 @@ class RuntimeService
}
/**
* 绑定动态配置
* 绑定动态配置.
* @param array $data 配置数据
* @return boolean 是否调试模式
* @return bool 是否调试模式
*/
public static function apply(array $data = []): bool
{
@ -162,8 +163,7 @@ class RuntimeService
}
/**
* 压缩发布项目
* @return string
* 压缩发布项目.
*/
public static function push(): string
{
@ -174,25 +174,29 @@ class RuntimeService
}
/**
* 判断运行环境
* 判断运行环境.
* @param string $type 运行模式dev|demo|local
* @return boolean
*/
public static function check(string $type = 'dev'): bool
{
$domain = Library::$sapp->request->host(true);
$isDemo = boolval(preg_match('|v\d+\.thinkadmin\.top|', $domain));
$isLocal = $domain === '127.0.0.1' || is_numeric(stripos($domain, 'local'));
if ($type === static::MODE_DEVE) return $isLocal || $isDemo;
if ($type === static::MODE_DEMO) return $isDemo;
if ($type === static::MODE_LOCAL) return $isLocal;
if ($type === static::MODE_DEVE) {
return $isLocal || $isDemo;
}
if ($type === static::MODE_DEMO) {
return $isDemo;
}
if ($type === static::MODE_LOCAL) {
return $isLocal;
}
return true;
}
/**
* 清理运行缓存
* @param boolean $force 清理目录
* @return boolean
* 清理运行缓存.
* @param bool $force 清理目录
*/
public static function clear(bool $force = true): bool
{
@ -203,8 +207,7 @@ class RuntimeService
}
/**
* 开发模式运行
* @return boolean
* 开发模式运行.
*/
public static function isDebug(): bool
{
@ -212,8 +215,7 @@ class RuntimeService
}
/**
* 生产模式运行
* @return boolean
* 生产模式运行.
*/
public static function isOnline(): bool
{
@ -221,10 +223,7 @@ class RuntimeService
}
/**
* 初始化主程序
* @param ?\think\App $app
* @param ?\think\Request $request
* @return \think\Response
* 初始化主程序.
*/
public static function doWebsiteInit(?App $app = null, ?Request $request = null): Response
{
@ -237,9 +236,7 @@ class RuntimeService
}
/**
* 初始化命令行
* @param ?\think\App $app
* @return integer
* 初始化命令行.
*/
public static function doConsoleInit(?App $app = null): int
{
@ -252,12 +249,11 @@ class RuntimeService
}
/**
* 生成唯一数组
* 生成唯一数组.
* @param array ...$args
* @return array
*/
private static function uniqueMergeArray(...$args): array
{
return array_unique(array_reverse(array_merge(...$args)));
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
@ -35,7 +37,6 @@ use think\Model;
/**
* 系统参数管理服务
* @class SystemService
* @package think\admin\service
*
* @method static bool isDebug() 调式模式运行
* @method static bool isOnline() 产品模式运行
@ -57,29 +58,75 @@ use think\Model;
class SystemService extends Service
{
/**
* 生成静态路径链接
* 魔术方法调用(临时).
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws Exception
*/
public function __call(string $method, array $arguments)
{
return static::__callStatic($method, $arguments);
}
/**
* 静态方法兼容(临时).
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
$map = [
'setRuntime' => 'set',
'getRuntime' => 'get',
'bindRuntime' => 'apply',
'isDebug' => 'isDebug',
'isOnline' => 'isOnline',
'doInit' => 'doWebsiteInit',
'doConsoleInit' => 'doConsoleInit',
'pushRuntime' => 'push',
'clearRuntime' => 'clear',
'checkRunMode' => 'check',
];
switch (strtolower($method)) {
case 'setconfig':
return self::setData(...$arguments);
case 'getconfig':
return self::getData(...$arguments);
}
if (isset($map[$method])) {
return RuntimeService::{$map[$method]}(...$arguments);
}
throw new Exception("method not exists: RuntimeService::{$method}()");
}
/**
* 生成静态路径链接.
* @param string $path 后缀路径
* @param ?string $type 路径类型
* @param mixed $default 默认数据
* @return string|array
* @return array|string
*/
public static function uri(string $path = '', ?string $type = '__ROOT__', $default = '')
{
$plugin = Library::$sapp->http->getName();
if (strlen($path)) $path = '/' . ltrim($path, '/');
$prefix = rtrim(dirname(Library::$sapp->request->basefile()), '\\/');
if (strlen($path)) {
$path = '/' . ltrim($path, '/');
}
$prefix = rtrim(dirname(Library::$sapp->request->basefile()), '\/');
$data = [
'__APP__' => rtrim(url('@')->build(), '\\/') . $path,
'__APP__' => rtrim(url('@')->build(), '\/') . $path,
'__ROOT__' => $prefix . $path,
'__PLUG__' => "{$prefix}/static/extra/{$plugin}{$path}",
'__FULL__' => Library::$sapp->request->domain() . $prefix . $path
'__FULL__' => Library::$sapp->request->domain() . $prefix . $path,
];
return is_null($type) ? $data : ($data[$type] ?? $default);
}
/**
* 生成全部静态路径
* @param string $path
* 生成全部静态路径.
* @return string[]
*/
public static function uris(string $path = ''): array
@ -88,11 +135,11 @@ class SystemService extends Service
}
/**
* 设置配置数据
* 设置配置数据.
* @param string $name 配置名称
* @param mixed $value 配置内容
* @return integer|string
* @throws \think\admin\Exception
* @return int|string
* @throws Exception
*/
public static function set(string $name, $value = '')
{
@ -103,7 +150,7 @@ class SystemService extends Service
$count += static::set("{$field}.{$kk}", $vv);
}
return $count;
} else try {
} try {
$map = ['type' => $type, 'name' => $field];
SystemConfig::mk()->master()->where($map)->findOrEmpty()->save(array_merge($map, ['value' => $value]));
sysvar('think.admin.config', []);
@ -115,11 +162,9 @@ class SystemService extends Service
}
/**
* 读取配置数据
* @param string $name
* @param string $default
* 读取配置数据.
* @return array|mixed|string
* @throws \think\admin\Exception
* @throws Exception
*/
public static function get(string $name = '', string $default = '')
{
@ -133,42 +178,48 @@ class SystemService extends Service
[$type, $field, $outer] = static::_parse($name);
if (empty($name)) {
return $config;
} elseif (isset($config[$type])) {
}
if (isset($config[$type])) {
$group = $config[$type];
if ($outer !== 'raw') foreach ($group as $kk => $vo) {
$group[$kk] = htmlspecialchars(strval($vo));
if ($outer !== 'raw') {
foreach ($group as $kk => $vo) {
$group[$kk] = htmlspecialchars(strval($vo));
}
}
return $field ? ($group[$field] ?? $default) : $group;
} else {
return $default;
}
return $default;
} catch (\Exception $exception) {
throw new Exception($exception->getMessage(), $exception->getCode());
}
}
/**
* 数据增量保存
* 数据增量保存.
* @param Model|Query|string $query 数据查询对象
* @param array $data 需要保存的数据,成功返回对应模型
* @param string $key 更新条件查询主键
* @param mixed $map 额外更新查询条件
* @return boolean|integer 失败返回 false, 成功返回主键值或 true
* @throws \think\admin\Exception
* @return bool|int 失败返回 false, 成功返回主键值或 true
* @throws Exception
*/
public static function save($query, array &$data, string $key = 'id', $map = [])
{
try {
$query = Helper::buildQuery($query)->master()->strict(false);
if (empty($map[$key])) $query->where([$key => $data[$key] ?? null]);
if (empty($map[$key])) {
$query->where([$key => $data[$key] ?? null]);
}
$model = $query->where($map)->findOrEmpty();
// 当前操作方法描述
$action = $model->isExists() ? 'onAdminUpdate' : 'onAdminInsert';
// 写入或更新模型数据
if ($model->save($data) === false) return false;
if ($model->save($data) === false) {
return false;
}
// 模型自定义事件回调
if ($model instanceof \think\admin\Model) {
$model->$action(strval($model->getAttr($key)));
$model->{$action}(strval($model->getAttr($key)));
}
$data = $model->toArray();
return $model[$key] ?? true;
@ -178,19 +229,21 @@ class SystemService extends Service
}
/**
* 批量更新保存数据
* 批量更新保存数据.
* @param Model|Query|string $query 数据查询对象
* @param array $data 需要保存的数据,成功返回对应模型
* @param string $key 更新条件查询主键
* @param mixed $map 额外更新查询条件
* @return boolean|integer 失败返回 false, 成功返回主键值或 true
* @throws \think\admin\Exception
* @return bool|int 失败返回 false, 成功返回主键值或 true
* @throws Exception
*/
public static function update($query, array $data, string $key = 'id', $map = [])
{
try {
$query = Helper::buildQuery($query)->master()->where($map);
if (empty($map[$key])) $query->where([$key => $data[$key] ?? null]);
if (empty($map[$key])) {
$query->where([$key => $data[$key] ?? null]);
}
return (clone $query)->count() > 1 ? $query->strict(false)->update($data) : $query->findOrEmpty()->save($data);
} catch (\Exception|\Throwable $exception) {
throw new Exception($exception->getMessage(), $exception->getCode());
@ -198,22 +251,7 @@ class SystemService extends Service
}
/**
* 解析缓存名称
* @param string $rule 配置名称
* @return array
*/
private static function _parse(string $rule): array
{
$type = 'base';
if (stripos($rule, '.') !== false) {
[$type, $rule] = explode('.', $rule, 2);
}
[$field, $outer] = explode('|', "{$rule}|");
return [$type, $field, strtolower($outer)];
}
/**
* 获取数据库所有数据表
* 获取数据库所有数据表.
* @return array [table, total, count]
*/
public static function getTables(): array
@ -223,18 +261,20 @@ class SystemService extends Service
}
/**
* 复制并创建表结构
* 复制并创建表结构.
* @param string $from 来源表名
* @param string $create 创建表名
* @param array $tables 现有表集合
* @param boolean $copy 是否复制
* @param bool $copy 是否复制
* @param mixed $where 复制条件
* @throws \think\admin\Exception
* @throws Exception
*/
public static function copyTableStruct(string $from, string $create, array $tables = [], bool $copy = false, $where = [])
{
try {
if (empty($tables)) [$tables] = static::getTables();
if (empty($tables)) {
[$tables] = static::getTables();
}
if (!in_array($from, $tables)) {
throw new Exception("待复制的数据表 {$from} 不存在!");
}
@ -251,11 +291,10 @@ class SystemService extends Service
}
/**
* 保存数据内容
* 保存数据内容.
* @param string $name 数据名称
* @param mixed $value 数据内容
* @return boolean
* @throws \think\admin\Exception
* @throws Exception
*/
public static function setData(string $name, $value): bool
{
@ -268,7 +307,7 @@ class SystemService extends Service
}
/**
* 读取数据内容
* 读取数据内容.
* @param string $name 数据名称
* @param mixed $default 默认内容
* @return mixed
@ -278,7 +317,9 @@ class SystemService extends Service
try {
// 读取原始序列化或JSON数据
$value = SystemData::mk()->where(['name' => $name])->value('value');
if (is_null($value)) return $default;
if (is_null($value)) {
return $default;
}
if (is_string($value) && strpos($value, '[') === 0) {
return json_decode($value, true)[0];
}
@ -306,10 +347,7 @@ class SystemService extends Service
}
/**
* 写入系统日志内容
* @param string $action
* @param string $content
* @return boolean
* 写入系统日志内容.
*/
public static function setOplog(string $action, string $content): bool
{
@ -317,27 +355,24 @@ class SystemService extends Service
}
/**
* 获取系统日志内容
* @param string $action
* @param string $content
* @return array
* 获取系统日志内容.
*/
public static function getOplog(string $action, string $content): array
{
return [
'node' => NodeService::getCurrent(),
'action' => lang($action), 'content' => lang($content),
'geoip' => Library::$sapp->request->ip() ?: '127.0.0.1',
'username' => AdminService::getUserName() ?: '-',
'node' => NodeService::getCurrent(),
'action' => lang($action), 'content' => lang($content),
'geoip' => Library::$sapp->request->ip() ?: '127.0.0.1',
'username' => AdminService::getUserName() ?: '-',
'create_at' => date('Y-m-d H:i:s'),
];
}
/**
* 打印输出数据到文件
* 打印输出数据到文件.
* @param mixed $data 输出的数据
* @param boolean $new 强制替换文件
* @param string|null $file 文件名称
* @param bool $new 强制替换文件
* @param null|string $file 文件名称
* @return false|int
*/
public static function putDebug($data, bool $new = false, ?string $file = null)
@ -345,17 +380,19 @@ class SystemService extends Service
ob_start();
var_dump($data);
$output = preg_replace('/]=>\n(\s+)/m', '] => ', ob_get_clean());
if (is_null($file)) $file = syspath('runtime/' . date('Ymd') . '.log');
else if (!preg_match('#[/\\\\]+#', $file)) $file = syspath("runtime/{$file}.log");
if (is_null($file)) {
$file = syspath('runtime/' . date('Ymd') . '.log');
} elseif (!preg_match('#[/\\\]+#', $file)) {
$file = syspath("runtime/{$file}.log");
}
is_dir($dir = dirname($file)) or mkdir($dir, 0777, true);
return $new ? file_put_contents($file, $output) : file_put_contents($file, $output, FILE_APPEND);
}
/**
* 设置网页标签图标
* 设置网页标签图标.
* @param ?string $icon 网页标签图标
* @return boolean
* @throws \think\admin\Exception
* @throws Exception
*/
public static function setFavicon(?string $icon = null): bool
{
@ -371,7 +408,9 @@ class SystemService extends Service
$name = Storage::name($icon, 'tmp', 'icon');
$info = LocalStorage::instance()->set($name, Storage::curlGet($icon), true);
}
if (empty($info) || empty($info['file'])) return false;
if (empty($info) || empty($info['file'])) {
return false;
}
$favicon = new FaviconExtend($info['file'], [48, 48]);
return $favicon->saveIco(syspath('public/favicon.ico'));
} catch (Exception $exception) {
@ -383,49 +422,16 @@ class SystemService extends Service
}
/**
* 魔术方法调用(临时)
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws \think\admin\Exception
* 解析缓存名称.
* @param string $rule 配置名称
*/
public function __call(string $method, array $arguments)
private static function _parse(string $rule): array
{
return static::__callStatic($method, $arguments);
}
/**
* 静态方法兼容(临时)
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws \think\admin\Exception
*/
public static function __callStatic(string $method, array $arguments)
{
$map = [
'setRuntime' => 'set',
'getRuntime' => 'get',
'bindRuntime' => 'apply',
'isDebug' => 'isDebug',
'isOnline' => 'isOnline',
'doInit' => 'doWebsiteInit',
'doConsoleInit' => 'doConsoleInit',
'pushRuntime' => 'push',
'clearRuntime' => 'clear',
'checkRunMode' => 'check',
];
switch (strtolower($method)) {
case 'setconfig':
return self::setData(...$arguments);
case 'getconfig':
return self::getData(...$arguments);
}
if (isset($map[$method])) {
return RuntimeService::{$map[$method]}(...$arguments);
} else {
throw new Exception("method not exists: RuntimeService::{$method}()");
$type = 'base';
if (stripos($rule, '.') !== false) {
[$type, $rule] = explode('.', $rule, 2);
}
[$field, $outer] = explode('|', "{$rule}|");
return [$type, $field, strtolower($outer)];
}
}

View File

@ -1,23 +1,26 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\service;
use think\admin\Exception;
use think\admin\extend\HttpExtend;
use think\admin\Service;
@ -25,18 +28,11 @@ use think\admin\Service;
* 新助通短信接口服务
* @class ZtSmsService
* @deprecated 独立封装为插件
* @package think\admin\service
*/
class ZtSmsService extends Service
{
/**
* 接口地址
* @var string
*/
private $api = 'https://api.mix2.zthysms.com';
/**
* 子账号名称
* 子账号名称.
* @var string
*/
protected $username;
@ -48,17 +44,13 @@ class ZtSmsService extends Service
protected $password;
/**
* 短信服务初始化
* @throws \think\admin\Exception
* 接口地址
* @var string
*/
protected function initialize()
{
$this->username = sysconf('ztsms.username|raw') ?: '';
$this->password = sysconf('ztsms.password|raw') ?: '';
}
private $api = 'https://api.mix2.zthysms.com';
/**
* 短信服务初始化
* 短信服务初始化.
* @param string $username 账号名称
* @param string $password 账号密码
* @return static
@ -75,7 +67,6 @@ class ZtSmsService extends Service
* @param string $code 验证码
* @param string $phone 手机号验证
* @param string $template 模板编码
* @return boolean
*/
public function checkVerifyCode(string $code, string $phone, string $template = 'ztsms.register_verify'): bool
{
@ -83,18 +74,16 @@ class ZtSmsService extends Service
if (is_array($cache) && isset($cache['code']) && $cache['code'] == $code) {
$this->app->cache->delete($ckey);
return true;
} else {
return false;
}
return false;
}
/**
* 验证手机短信验证码
* @param string $phone 手机号码
* @param integer $wait 等待时间
* @param int $wait 等待时间
* @param string $template 模板编码
* @return array
* @throws \think\admin\Exception
* @throws Exception
*/
public function sendVerifyCode(string $phone, int $wait = 120, string $template = 'ztsms.register_verify'): array
{
@ -113,28 +102,27 @@ class ZtSmsService extends Service
[$state] = $this->timeSend($phone, str_replace('{code}', $code, $content));
if ($state) {
return [1, lang('短信验证码发送成功!'), ['time' => $wait]];
} else {
$this->app->cache->delete($ckey);
return [0, lang('短信发送失败,请稍候再试!'), ['time' => 0]];
}
$this->app->cache->delete($ckey);
return [0, lang('短信发送失败,请稍候再试!'), ['time' => 0]];
}
/**
* 创建短信签名
* 创建短信签名.
* @param array $signs 签名列表
* @param string $remark 签名备注
* @return array
*/
public function signAdd(array $signs = [], string $remark = ''): array
{
foreach ($signs as $key => $name) $signs[$key] = $this->_singName($name);
foreach ($signs as $key => $name) {
$signs[$key] = $this->_singName($name);
}
return $this->doRequest('/sms/v1/sign', ['sign' => $signs, 'remark' => $remark]);
}
/**
* 查询短信签名
* 查询短信签名.
* @param string $name 短信签名
* @return array
*/
public function signGet(string $name): array
{
@ -146,11 +134,10 @@ class ZtSmsService extends Service
/**
* 报备短信模板
* @param string $name 模板名称
* @param integer $type 模板类型1验证码, 2行业通知, 3营销推广)
* @param int $type 模板类型1验证码, 2行业通知, 3营销推广)
* @param string $content 模板内容
* @param array $params 模板变量
* @param string $remark 模板备注
* @return array
*/
public function tplAdd(string $name, int $type, string $content, array $params = [], string $remark = ''): array
{
@ -162,7 +149,6 @@ class ZtSmsService extends Service
/**
* 查询模板状态
* @param string $temId 短信模板
* @return array
*/
public function tplGet(string $temId): array
{
@ -174,7 +160,6 @@ class ZtSmsService extends Service
* @param string $tpId 短信模板
* @param string $sign 短信签名
* @param array $records 发送记录
* @return array
*/
public function tplSend(string $tpId, string $sign, array $records): array
{
@ -187,20 +172,19 @@ class ZtSmsService extends Service
* 发送定时短信
* @param string $mobile 发送手机号码
* @param string $content 发送短信内容
* @param integer $time 定时发送时间(为 0 立即发送)
* @return array
* @param int $time 定时发送时间(为 0 立即发送)
*/
public function timeSend(string $mobile, string $content, int $time = 0): array
{
$data = ['mobile' => $mobile, 'content' => $content];
if ($time > 0) $data['time'] = $time;
if ($time > 0) {
$data['time'] = $time;
}
return $this->doRequest('/v2/sendSms', $data);
}
/**
* 批量发送短信
* @param array $records
* @return array
*/
public function batchSend(array $records): array
{
@ -208,7 +192,7 @@ class ZtSmsService extends Service
}
/**
* 短信条数查询
* 短信条数查询.
*/
public function balance(): array
{
@ -217,14 +201,26 @@ class ZtSmsService extends Service
}
/**
* 短信签名内容处理
* @param string $name
* @return string
* 短信服务初始化.
* @throws Exception
*/
protected function initialize()
{
$this->username = sysconf('ztsms.username|raw') ?: '';
$this->password = sysconf('ztsms.password|raw') ?: '';
}
/**
* 短信签名内容处理.
*/
private function _singName(string $name): string
{
if (strpos($name, '】') === false) $name = $name . '】';
if (strpos($name, '【') === false) $name = '【' . $name;
if (strpos($name, '】') === false) {
$name = $name . '】';
}
if (strpos($name, '【') === false) {
$name = '【' . $name;
}
return $name;
}
@ -232,7 +228,6 @@ class ZtSmsService extends Service
* 执行网络请求
* @param string $uri 接口请求地址
* @param array $data 接口请求参数
* @return array
*/
private function doRequest(string $uri, array $data): array
{
@ -242,22 +237,21 @@ class ZtSmsService extends Service
$result = json_decode(HttpExtend::post($this->api . $uri, json_encode(array_merge($data, $extends)), $options), true);
if (empty($result['code'])) {
return [0, [], lang('接口请求网络异常')];
} elseif (intval($result['code']) === 200) {
return [1, $result, lang($this->error($result['code']))];
} else {
return [0, $result, lang($this->error($result['code']))];
}
if (intval($result['code']) === 200) {
return [1, $result, lang($this->error($result['code']))];
}
return [0, $result, lang($this->error($result['code']))];
}
/**
* 获取状态描述
* @param integer $code 异常编号
* @return string
* 获取状态描述.
* @param int $code 异常编号
*/
private function error(int $code): string
{
$arrs = [
200 => '提交成功',
200 => '提交成功',
4001 => '用户名错误',
4002 => '密码不能为空',
4003 => '短信内容不能为空',
@ -293,4 +287,4 @@ class ZtSmsService extends Service
];
return $arrs[$code] ?? "{$code}";
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -27,39 +29,203 @@ use think\admin\Storage;
/**
* 阿里云OSS存储支持
* @class AliossStorage
* @package think\admin\storage
*/
class AliossStorage implements StorageInterface
{
use StorageUsageTrait;
/**
* 数据中心
* 数据中心.
* @var string
*/
private $point;
/**
* 存储空间名称
* 存储空间名称.
* @var string
*/
private $bucket;
/**
* AccessId
* AccessId.
* @var string
*/
private $accessKey;
/**
* AccessSecret
* AccessSecret.
* @var string
*/
private $secretKey;
/**
* 初始化入口
* @throws \think\admin\Exception
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$token = $this->token($name);
$data = ['key' => $name];
$data['policy'] = $token['policy'];
$data['Signature'] = $token['signature'];
$data['OSSAccessKeyId'] = $this->accessKey;
$data['success_action_status'] = '200';
if (is_string($attname) && strlen($attname) > 0) {
$data['Content-Disposition'] = 'inline;filename=' . urlencode($attname);
}
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
}
return [];
}
/**
* 读取文件内容.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, '204 No Content'));
}
/**
* 判断是否存在.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname, $name)}";
}
/**
* 获取存储路径.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息.
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
*/
public function upload(): string
{
$proc = $this->app->request->isSsl() ? 'https' : 'http';
return "{$proc}://{$this->bucket}.{$this->point}";
}
/**
* 获取上传令牌.
* @param string $name 文件名称
* @param int $expires 有效时间
* @param ?string $attname 下载名称
*/
public function token(string $name, int $expires = 3600, ?string $attname = null): array
{
$data = [
'policy' => base64_encode(json_encode([
'conditions' => [['content-length-range', 0, 1048576000]],
'expiration' => date('Y-m-d\TH:i:s.000\Z', time() + $expires),
])),
'keyid' => $this->accessKey,
'siteurl' => $this->url($name, false, $attname),
];
$data['signature'] = base64_encode(hash_hmac('sha1', $data['policy'], $this->secretKey, true));
return $data;
}
/**
* 获取存储区域
*/
public static function region(): array
{
return [
'oss-cn-hangzhou.aliyuncs.com' => lang('华东 1杭州'),
'oss-cn-shanghai.aliyuncs.com' => lang('华东 2上海'),
'oss-cn-nanjing.aliyuncs.com' => lang('华东 5南京本地地域'),
'oss-cn-fuzhou.aliyuncs.com' => lang('华东 6福州本地地域'),
'oss-cn-qingdao.aliyuncs.com' => lang('华北 1青岛'),
'oss-cn-beijing.aliyuncs.com' => lang('华北 2北京'),
'oss-cn-zhangjiakou.aliyuncs.com' => lang('华北 3张家口'),
'oss-cn-huhehaote.aliyuncs.com' => lang('华北 5呼和浩特'),
'oss-cn-wulanchabu.aliyuncs.com' => lang('华北 6乌兰察布'),
'oss-cn-shenzhen.aliyuncs.com' => lang('华南 1深圳'),
'oss-cn-heyuan.aliyuncs.com' => lang('华南 2河源'),
'oss-cn-guangzhou.aliyuncs.com' => lang('华南 3广州'),
'oss-cn-chengdu.aliyuncs.com' => lang('西南 1成都'),
'oss-cn-hongkong.aliyuncs.com' => lang('中国(香港)'),
'oss-us-west-1.aliyuncs.com' => lang('美国(硅谷)'),
'oss-us-east-1.aliyuncs.com' => lang('美国(弗吉尼亚)'),
'oss-ap-northeast-1.aliyuncs.com' => lang('日本(东京)'),
'oss-ap-northeast-2.aliyuncs.com' => lang('韩国(首尔)'),
'oss-ap-southeast-1.aliyuncs.com' => lang('新加坡'),
'oss-ap-southeast-2.aliyuncs.com' => lang('澳大利亚(悉尼)'),
'oss-ap-southeast-3.aliyuncs.com' => lang('马来西亚(吉隆坡)'),
'oss-ap-southeast-5.aliyuncs.com' => lang('印度尼西亚(雅加达)'),
'oss-ap-southeast-6.aliyuncs.com' => lang('菲律宾(马尼拉)'),
'oss-ap-southeast-7.aliyuncs.com' => lang('泰国(曼谷)'),
'oss-ap-south-1.aliyuncs.com' => lang('印度(孟买)'),
'oss-eu-central-1.aliyuncs.com' => lang('德国(法兰克福)'),
'oss-eu-west-1.aliyuncs.com' => lang('英国(伦敦)'),
'oss-me-east-1.aliyuncs.com' => lang('阿联酋(迪拜)'),
'oss-rg-china-mainland.aliyuncs.com' => lang('无地域属性(中国内地)'),
];
}
/**
* 初始化入口.
* @throws Exception
*/
protected function init()
{
@ -81,147 +247,9 @@ class AliossStorage implements StorageInterface
}
/**
* 上传文件内容
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$token = $this->token($name);
$data = ['key' => $name];
$data['policy'] = $token['policy'];
$data['Signature'] = $token['signature'];
$data['OSSAccessKeyId'] = $this->accessKey;
$data['success_action_status'] = '200';
if (is_string($attname) && strlen($attname) > 0) {
$data['Content-Disposition'] = 'inline;filename=' . urlencode($attname);
}
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
} else {
return [];
}
}
/**
* 读取文件内容
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, '204 No Content'));
}
/**
* 判断是否存在
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname,$name)}";
}
/**
* 获取存储路径
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
* @return string
*/
public function upload(): string
{
$proc = $this->app->request->isSsl() ? 'https' : 'http';
return "{$proc}://{$this->bucket}.{$this->point}";
}
/**
* 获取上传令牌
* @param string $name 文件名称
* @param integer $expires 有效时间
* @param ?string $attname 下载名称
* @return array
*/
public function token(string $name, int $expires = 3600, ?string $attname = null): array
{
$data = [
'policy' => base64_encode(json_encode([
'conditions' => [['content-length-range', 0, 1048576000]],
'expiration' => date('Y-m-d\TH:i:s.000\Z', time() + $expires),
])),
'keyid' => $this->accessKey,
'siteurl' => $this->url($name, false, $attname),
];
$data['signature'] = base64_encode(hash_hmac('sha1', $data['policy'], $this->secretKey, true));
return $data;
}
/**
* 请求数据签名
* 请求数据签名.
* @param string $method 请求方式
* @param string $soruce 资源名称
* @return array
*/
private function _sign(string $method, string $soruce): array
{
@ -241,46 +269,9 @@ class AliossStorage implements StorageInterface
$content = rawurldecode($content) . "/{$this->bucket}/{$soruce}";
$signature = base64_encode(hash_hmac('sha1', $content, $this->secretKey, true));
$header['Authorization'] = "OSS {$this->accessKey}:{$signature}";
foreach ($header as $key => $value) $header[$key] = "{$key}: {$value}";
foreach ($header as $key => $value) {
$header[$key] = "{$key}: {$value}";
}
return array_values($header);
}
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
return [
'oss-cn-hangzhou.aliyuncs.com' => lang('华东 1杭州'),
'oss-cn-shanghai.aliyuncs.com' => lang('华东 2上海'),
'oss-cn-nanjing.aliyuncs.com' => lang('华东 5南京本地地域'),
'oss-cn-fuzhou.aliyuncs.com' => lang('华东 6福州本地地域'),
'oss-cn-qingdao.aliyuncs.com' => lang('华北 1青岛'),
'oss-cn-beijing.aliyuncs.com' => lang('华北 2北京'),
'oss-cn-zhangjiakou.aliyuncs.com' => lang('华北 3张家口'),
'oss-cn-huhehaote.aliyuncs.com' => lang('华北 5呼和浩特'),
'oss-cn-wulanchabu.aliyuncs.com' => lang('华北 6乌兰察布'),
'oss-cn-shenzhen.aliyuncs.com' => lang('华南 1深圳'),
'oss-cn-heyuan.aliyuncs.com' => lang('华南 2河源'),
'oss-cn-guangzhou.aliyuncs.com' => lang('华南 3广州'),
'oss-cn-chengdu.aliyuncs.com' => lang('西南 1成都'),
'oss-cn-hongkong.aliyuncs.com' => lang('中国(香港)'),
'oss-us-west-1.aliyuncs.com' => lang('美国(硅谷)'),
'oss-us-east-1.aliyuncs.com' => lang('美国(弗吉尼亚)'),
'oss-ap-northeast-1.aliyuncs.com' => lang('日本(东京)'),
'oss-ap-northeast-2.aliyuncs.com' => lang('韩国(首尔)'),
'oss-ap-southeast-1.aliyuncs.com' => lang('新加坡'),
'oss-ap-southeast-2.aliyuncs.com' => lang('澳大利亚(悉尼)'),
'oss-ap-southeast-3.aliyuncs.com' => lang('马来西亚(吉隆坡)'),
'oss-ap-southeast-5.aliyuncs.com' => lang('印度尼西亚(雅加达)'),
'oss-ap-southeast-6.aliyuncs.com' => lang('菲律宾(马尼拉)'),
'oss-ap-southeast-7.aliyuncs.com' => lang('泰国(曼谷)'),
'oss-ap-south-1.aliyuncs.com' => lang('印度(孟买)'),
'oss-eu-central-1.aliyuncs.com' => lang('德国(法兰克福)'),
'oss-eu-west-1.aliyuncs.com' => lang('英国(伦敦)'),
'oss-me-east-1.aliyuncs.com' => lang('阿联酋(迪拜)'),
'oss-rg-china-mainland.aliyuncs.com' => lang('无地域属性(中国内地)')
];
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -27,14 +29,13 @@ use think\admin\Storage;
/**
* Alist 自建存储支持
* @class AlistStorage
* @package think\admin\storage
*/
class AlistStorage implements StorageInterface
{
use StorageUsageTrait;
/**
* 用户账号
* 用户账号.
* @var string
*/
protected $username;
@ -46,7 +47,7 @@ class AlistStorage implements StorageInterface
protected $password;
/**
* 保存路径
* 保存路径.
* @var string
*/
protected $savepath;
@ -58,57 +59,31 @@ class AlistStorage implements StorageInterface
protected $cachekey;
/**
* 存储引擎初始化
* @return void
* @throws \think\admin\Exception
*/
protected function init()
{
$host = strtolower(sysconf('storage.alist_http_domain|raw'));
$type = strtolower(sysconf('storage.alist_http_protocol|raw'));
if (!empty($host) && $type === 'auto') {
$this->domain = "//{$host}";
} elseif (!empty($host) && in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$host}";
} else {
throw new Exception(lang('未配置Alist域名'));
}
$this->username = sysconf('storage.alist_username|raw') ?: '';
$this->password = sysconf('storage.alist_password|raw') ?: '';
$this->savepath = trim(sysconf('storage.alist_savepath|raw') ?: '', '\\/');
$this->savepath = $this->savepath ? "{$this->savepath}/" : '';
$this->cachekey = md5($this->domain . $this->username . $this->password);
}
/**
* 上传文件内容
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
* @throws \think\admin\Exception
* @throws Exception
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
$header = ["Authorization: {$this->token()}", "file-path:" . urlencode($this->real($name))];
$header = ["Authorization: {$this->token()}", 'file-path:' . urlencode($this->real($name))];
$result = HttpExtend::submit("{$this->domain}/api/fs/form", [], $file, $header, 'PUT', false);
if (is_array($data = json_decode($result, true))) {
if ($data['code'] === 200 && $data['message'] === 'success') {
return $this->info($name, $safe);
} else {
throw new Exception($data['message'] ?? '接口请求失败!', intval($data['code'] ?? 0));
}
throw new Exception($data['message'] ?? '接口请求失败!', intval($data['code'] ?? 0));
}
return [];
}
/**
* 读取文件内容
* 读取文件内容.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
@ -116,10 +91,9 @@ class AlistStorage implements StorageInterface
}
/**
* 删除存储文件
* 删除存储文件.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
@ -134,16 +108,15 @@ class AlistStorage implements StorageInterface
}
/**
* 判断是否存在
* 判断是否存在.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
try {
$this->httpPost('/api/fs/get', [
'path' => $this->real($name)
'path' => $this->real($name),
]);
return true;
} catch (\Exception $exception) {
@ -152,23 +125,18 @@ class AlistStorage implements StorageInterface
}
/**
* 获取文件下载链接
* @param string $name
* @param bool $safe
* @param string|null $attname
* @return string
* 获取文件下载链接.
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
$path = rtrim($this->userPath(), '\\/') . $this->real($name);
return "{$this->domain}/d{$this->delSuffix($path)}{$this->getSuffix($attname,$path)}";
$path = rtrim($this->userPath(), '\/') . $this->real($name);
return "{$this->domain}/d{$this->delSuffix($path)}{$this->getSuffix($attname, $path)}";
}
/**
* 获取存储路径
* 获取存储路径.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
@ -176,24 +144,22 @@ class AlistStorage implements StorageInterface
}
/**
* 获取文件信息
* 获取文件信息.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'key' => $name,
'url' => $this->url($name, $safe, $attname),
'key' => $name,
'url' => $this->url($name, $safe, $attname),
'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
* @return string
*/
public function upload(): string
{
@ -202,7 +168,6 @@ class AlistStorage implements StorageInterface
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
@ -210,15 +175,66 @@ class AlistStorage implements StorageInterface
}
/**
* 创建目录
* @param string $path
* @return boolean
* 转换为绝对路径.
*/
public function real(string $path): string
{
return "/{$this->savepath}" . trim($path, '\/');
}
/**
* 获取用户 Token 信息.
* @throws Exception
*/
public function token(bool $force = false): string
{
try {
$skey = "{$this->cachekey}.token";
if (empty($force) && ($token = $this->app->cache->get($skey))) {
return $token;
}
$data = ['Password' => $this->password, 'Username' => $this->username];
$body = $this->httpPost('/api/auth/login', $data, false);
if (!empty($body['data']['token'])) {
$this->app->cache->set($skey, $body['data']['token'], 60);
return $body['data']['token'];
}
throw new Exception('获取用户 Token 失败!');
} catch (\Exception $exception) {
throw new Exception($exception->getMessage());
}
}
/**
* 存储引擎初始化.
* @throws Exception
*/
protected function init()
{
$host = strtolower(sysconf('storage.alist_http_domain|raw'));
$type = strtolower(sysconf('storage.alist_http_protocol|raw'));
if (!empty($host) && $type === 'auto') {
$this->domain = "//{$host}";
} elseif (!empty($host) && in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$host}";
} else {
throw new Exception(lang('未配置Alist域名'));
}
$this->username = sysconf('storage.alist_username|raw') ?: '';
$this->password = sysconf('storage.alist_password|raw') ?: '';
$this->savepath = trim(sysconf('storage.alist_savepath|raw') ?: '', '\/');
$this->savepath = $this->savepath ? "{$this->savepath}/" : '';
$this->cachekey = md5($this->domain . $this->username . $this->password);
}
/**
* 创建目录.
*/
protected function mkdir(string $path): bool
{
try {
$this->httpPost('/api/fs/mkdir', [
'path' => $this->real($path)
'path' => $this->real($path),
]);
return true;
} catch (\Exception $exception) {
@ -227,51 +243,20 @@ class AlistStorage implements StorageInterface
}
/**
* 转换为绝对路径
* @param string $path
* @return string
*/
public function real(string $path): string
{
return "/{$this->savepath}" . trim($path, '\\/');
}
/**
* 获取用户 Token 信息
* @param boolean $force
* @return string
* @throws \think\admin\Exception
*/
public function token(bool $force = false): string
{
try {
$skey = "{$this->cachekey}.token";
if (empty($force) && ($token = $this->app->cache->get($skey))) return $token;
$data = ['Password' => $this->password, 'Username' => $this->username];
$body = $this->httpPost("/api/auth/login", $data, false);
if (!empty($body['data']['token'])) {
$this->app->cache->set($skey, $body['data']['token'], 60);
return $body['data']['token'];
} else {
throw new Exception('获取用户 Token 失败!');
}
} catch (\Exception $exception) {
throw new Exception($exception->getMessage());
}
}
/**
* 获取基础路径
* @return string
* 获取基础路径.
*/
private function userPath(): string
{
try {
$skey = "{$this->cachekey}.path";
if ($path = $this->app->cache->get($skey)) return $path;
if ($path = $this->app->cache->get($skey)) {
return $path;
}
$data = $this->httGet('/api/me');
if (empty($data['data']['base_path'])) return '/';
$path = trim($data['data']['base_path'], '\\/');
if (empty($data['data']['base_path'])) {
return '/';
}
$path = trim($data['data']['base_path'], '\/');
$this->app->cache->set($skey, $path = $path ? "/{$path}/" : '/', 60);
return $path;
} catch (\Exception $exception) {
@ -280,43 +265,39 @@ class AlistStorage implements StorageInterface
}
/**
* Get 提交数据
* @param string $uri
* @return array
* @throws \think\admin\Exception
* Get 提交数据.
* @throws Exception
*/
private function httGet(string $uri): array
{
$header = ["Authorization: {$this->token()}"];
$header[] = "Content-Type: application/json;charset=UTF-8";
$header[] = 'Content-Type: application/json;charset=UTF-8';
$result = HttpExtend::get($this->domain . $uri, [], ['headers' => $header]);
if (is_array($data = json_decode($result, true))) {
if ($data['code'] === 200 && $data['message'] === 'success') return $data;
if ($data['code'] === 200 && $data['message'] === 'success') {
return $data;
}
throw new Exception($data['message'] ?? '接口请求失败!', intval($data['code'] ?? 0));
} else {
throw new Exception('接口请求失败!');
}
throw new Exception('接口请求失败!');
}
/**
* POST 提交数据
* @param string $uri
* @param array $body
* @param boolean $auth
* @return array
* @throws \think\admin\Exception
* POST 提交数据.
* @throws Exception
*/
private function httpPost(string $uri, array $body = [], bool $auth = true): array
{
$body = json_encode($body, JSON_UNESCAPED_UNICODE);
$header = $auth ? ["Authorization: {$this->token()}"] : [];
$header[] = "Content-Type: application/json;charset=UTF-8";
$header[] = 'Content-Type: application/json;charset=UTF-8';
$result = HttpExtend::post($this->domain . $uri, $body, ['headers' => $header]);
if (is_array($data = json_decode($result, true))) {
if ($data['code'] === 200 && $data['message'] === 'success') return $data;
if ($data['code'] === 200 && $data['message'] === 'success') {
return $data;
}
throw new Exception($data['message'] ?? '接口请求失败!', intval($data['code'] ?? 0));
} else {
throw new Exception('接口请求失败!');
}
throw new Exception('接口请求失败!');
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -24,38 +26,17 @@ use think\admin\contract\StorageUsageTrait;
/**
* 本地存储支持
* @class LocalStorage
* @package think\admin\storage
*/
class LocalStorage implements StorageInterface
{
use StorageUsageTrait;
/**
* 初始化入口
* @throws \think\admin\Exception
*/
protected function init()
{
$type = sysconf('storage.local_http_protocol|raw') ?: 'follow';
if ($type === 'follow') $type = $this->app->request->scheme();
$this->domain = trim(dirname($this->app->request->baseFile()), '\\/');
if ($type !== 'path') {
$domain = sysconf('storage.local_http_domain|raw') ?: $this->app->request->host();
if ($type === 'auto') {
$this->domain = "//{$domain}";
} elseif (in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$domain}";
}
}
}
/**
* 上传文件内容
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
@ -71,37 +52,35 @@ class LocalStorage implements StorageInterface
}
/**
* 读取文件内容
* 读取文件内容.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
if (!$this->has($name, $safe)) return '';
if (!$this->has($name, $safe)) {
return '';
}
return file_get_contents($this->path($name, $safe));
}
/**
* 删除存储文件
* 删除存储文件.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
if ($this->has($name, $safe)) {
return @unlink($this->path($name, $safe));
} else {
return false;
}
return false;
}
/**
* 判断是否存在
* 判断是否存在.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
@ -111,20 +90,18 @@ class LocalStorage implements StorageInterface
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return $safe ? $name : "{$this->domain}/upload/{$this->delSuffix($name)}{$this->getSuffix($attname,$name)}";
return $safe ? $name : "{$this->domain}/upload/{$this->delSuffix($name)}{$this->getSuffix($attname, $name)}";
}
/**
* 获取存储路径
* 获取存储路径.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
@ -133,11 +110,10 @@ class LocalStorage implements StorageInterface
}
/**
* 获取文件信息
* 获取文件信息.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
@ -149,7 +125,6 @@ class LocalStorage implements StorageInterface
/**
* 获取上传地址
* @return string
*/
public function upload(): string
{
@ -158,10 +133,30 @@ class LocalStorage implements StorageInterface
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
return [];
}
}
/**
* 初始化入口.
* @throws \think\admin\Exception
*/
protected function init()
{
$type = sysconf('storage.local_http_protocol|raw') ?: 'follow';
if ($type === 'follow') {
$type = $this->app->request->scheme();
}
$this->domain = trim(dirname($this->app->request->baseFile()), '\/');
if ($type !== 'path') {
$domain = sysconf('storage.local_http_domain|raw') ?: $this->app->request->host();
if ($type === 'auto') {
$this->domain = "//{$domain}";
} elseif (in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$domain}";
}
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -27,74 +29,50 @@ use think\admin\Storage;
/**
* 七牛云存储支持
* @class QiniuStorage
* @package think\admin\storage
*/
class QiniuStorage implements StorageInterface
{
use StorageUsageTrait;
private $bucket;
private $accessKey;
private $secretKey;
/**
* 初始化入口
* @throws \think\admin\Exception
*/
protected function init()
{
// 读取配置文件
$this->bucket = sysconf('storage.qiniu_bucket|raw');
$this->accessKey = sysconf('storage.qiniu_access_key|raw');
$this->secretKey = sysconf('storage.qiniu_secret_key|raw');
// 计算链接前缀
$host = strtolower(sysconf('storage.qiniu_http_domain|raw'));
$type = strtolower(sysconf('storage.qiniu_http_protocol|raw'));
if ($type === 'auto') {
$this->domain = "//{$host}";
} elseif (in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$host}";
} else {
throw new Exception(lang('未配置七牛云域名'));
}
}
/**
* 上传文件内容
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
* @throws \think\admin\Exception
* @throws Exception
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$token = $this->token($name, 3600, $attname);
$data = ['key' => $name, 'token' => $token, 'fileName' => $name];
$file = ['field' => "file", 'name' => $name, 'content' => $file];
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
$result = HttpExtend::submit($this->upload(), $data, $file, [], 'POST', false);
return json_decode($result, true);
}
/**
* 读取文件内容
* 读取文件内容.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
$url = $this->url($name, $safe) . "?e=" . time();
$url = $this->url($name, $safe) . '?e=' . time();
$token = "{$this->accessKey}:{$this->safeBase64(hash_hmac('sha1', $url, $this->secretKey, true))}";
return Storage::curlGet("{$url}&token={$token}");
}
/**
* 删除存储文件
* 删除存储文件.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
@ -106,10 +84,9 @@ class QiniuStorage implements StorageInterface
}
/**
* 判断是否存在
* 判断是否存在.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
@ -119,20 +96,18 @@ class QiniuStorage implements StorageInterface
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname,$name)}";
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname, $name)}";
}
/**
* 获取存储路径
* 获取存储路径.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
@ -140,11 +115,10 @@ class QiniuStorage implements StorageInterface
}
/**
* 获取文件信息
* 获取文件信息.
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
@ -155,8 +129,7 @@ class QiniuStorage implements StorageInterface
/**
* 获取上传地址
* @return string
* @throws \think\admin\Exception
* @throws Exception
*/
public function upload(): string
{
@ -193,27 +166,62 @@ class QiniuStorage implements StorageInterface
}
/**
* 生成上传令牌
* 生成上传令牌.
* @param ?string $name 文件名称
* @param integer $expires 有效时间
* @param int $expires 有效时间
* @param ?string $attname 下载名称
* @return string
*/
public function token(?string $name = null, int $expires = 3600, ?string $attname = null): string
{
$key = is_null($name) ? '$(key)' : $name;
$url = "{$this->domain}/$(key){$this->getSuffix($attname,$name)}";
$url = "{$this->domain}/$(key){$this->getSuffix($attname, $name)}";
$policy = $this->safeBase64(json_encode([
"deadline" => time() + $expires, "scope" => is_null($name) ? $this->bucket : "{$this->bucket}:{$name}",
'deadline' => time() + $expires, 'scope' => is_null($name) ? $this->bucket : "{$this->bucket}:{$name}",
'returnBody' => json_encode(['uploaded' => true, 'filename' => '$(key)', 'url' => $url, 'key' => $key, 'file' => $key], JSON_UNESCAPED_UNICODE),
]));
return "{$this->accessKey}:{$this->safeBase64(hash_hmac('sha1', $policy, $this->secretKey, true))}:{$policy}";
}
/**
* 获取存储区域
*/
public static function region(): array
{
return [
'up.qiniup.com' => lang('华东-浙江'),
'up-cn-east-2.qiniup.com' => lang('华东-浙江2'),
'up-z1.qiniup.com' => lang('华北-河北'),
'up-z2.qiniup.com' => lang('华南-广东'),
'up-na0.qiniup.com' => lang('北美-洛杉矶'),
'up-as0.qiniup.com' => lang('亚太-新加坡'),
'up-ap-northeast-1.qiniup.com' => lang('亚太-首尔'),
];
}
/**
* 初始化入口.
* @throws Exception
*/
protected function init()
{
// 读取配置文件
$this->bucket = sysconf('storage.qiniu_bucket|raw');
$this->accessKey = sysconf('storage.qiniu_access_key|raw');
$this->secretKey = sysconf('storage.qiniu_secret_key|raw');
// 计算链接前缀
$host = strtolower(sysconf('storage.qiniu_http_domain|raw'));
$type = strtolower(sysconf('storage.qiniu_http_protocol|raw'));
if ($type === 'auto') {
$this->domain = "//{$host}";
} elseif (in_array($type, ['http', 'https'])) {
$this->domain = "{$type}://{$host}";
} else {
throw new Exception(lang('未配置七牛云域名'));
}
}
/**
* 安全BASE64编码
* @param string $content
* @return string
*/
private function safeBase64(string $content): string
{
@ -224,7 +232,6 @@ class QiniuStorage implements StorageInterface
* 生成管理凭证
* @param string $name 文件名称
* @param string $type 操作类型
* @return array
*/
private function getAccessToken(string $name, string $type = 'stat'): array
{
@ -232,21 +239,4 @@ class QiniuStorage implements StorageInterface
$sign = hash_hmac('sha1', "/{$type}/{$entry}\n", $this->secretKey, true);
return [$entry, "{$this->accessKey}:{$this->safeBase64($sign)}"];
}
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
return [
'up.qiniup.com' => lang('华东-浙江'),
'up-cn-east-2.qiniup.com' => lang('华东-浙江2'),
'up-z1.qiniup.com' => lang('华北-河北'),
'up-z2.qiniup.com' => lang('华南-广东'),
'up-na0.qiniup.com' => lang('北美-洛杉矶'),
'up-as0.qiniup.com' => lang('亚太-新加坡'),
'up-ap-northeast-1.qiniup.com' => lang('亚太-首尔'),
];
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -27,40 +29,196 @@ use think\admin\Storage;
/**
* 腾讯云COS存储支持
* @class TxcosStorage
* @package think\admin\storage
*/
class TxcosStorage implements StorageInterface
{
use StorageUsageTrait;
/**
* 数据中心
* 数据中心.
* @var string
*/
private $point;
/**
* 存储空间名称
* 存储空间名称.
* @var string
*/
private $bucket;
/**
* $secretId
* $secretId.
* @var string
*/
private $secretId;
/**
* secretKey
* secretKey.
* @var string
*/
private $secretKey;
/**
* 初始化入口
* @throws \think\admin\Exception
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$data = $this->token($name) + ['key' => $name];
if (is_string($attname) && strlen($attname) > 0) {
$data['Content-Disposition'] = urlencode($attname);
}
$data['success_action_status'] = '200';
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
}
return [];
}
/**
* 读取文件内容.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, '204 No Content'));
}
/**
* 判断是否存在.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $name),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname, $name)}";
}
/**
* 获取存储路径.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息.
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
*/
public function upload(): string
{
$proc = $this->app->request->isSsl() ? 'https' : 'http';
return "{$proc}://{$this->bucket}.{$this->point}";
}
/**
* 生成上传令牌.
* @param string $name 文件名称
* @param int $expires 有效时间
* @param ?string $attname 下载名称
*/
public function token(string $name, int $expires = 3600, ?string $attname = null): array
{
$startTimestamp = time();
$endTimestamp = $startTimestamp + $expires;
$keyTime = "{$startTimestamp};{$endTimestamp}";
$siteurl = $this->url($name, false, $attname);
$policy = json_encode([
'expiration' => date('Y-m-d\TH:i:s.000\Z', $endTimestamp),
'conditions' => [['q-ak' => $this->secretId], ['q-sign-time' => $keyTime], ['q-sign-algorithm' => 'sha1']],
]);
return [
'policy' => base64_encode($policy), 'q-ak' => $this->secretId,
'siteurl' => $siteurl, 'q-key-time' => $keyTime, 'q-sign-algorithm' => 'sha1',
'q-signature' => hash_hmac('sha1', sha1($policy), hash_hmac('sha1', $keyTime, $this->secretKey)),
];
}
/**
* 获取存储区域
*/
public static function region(): array
{
return [
'cos.ap-beijing-1.myqcloud.com' => lang('中国大陆 公有云地域 北京一区'),
'cos.ap-beijing.myqcloud.com' => lang('中国大陆 公有云地域 北京'),
'cos.ap-nanjing.myqcloud.com' => lang('中国大陆 公有云地域 南京'),
'cos.ap-shanghai.myqcloud.com' => lang('中国大陆 公有云地域 上海'),
'cos.ap-guangzhou.myqcloud.com' => lang('中国大陆 公有云地域 广州'),
'cos.ap-chengdu.myqcloud.com' => lang('中国大陆 公有云地域 成都'),
'cos.ap-chongqing.myqcloud.com' => lang('中国大陆 公有云地域 重庆'),
'cos.ap-shenzhen-fsi.myqcloud.com' => lang('中国大陆 金融云地域 深圳金融'),
'cos.ap-shanghai-fsi.myqcloud.com' => lang('中国大陆 金融云地域 上海金融'),
'cos.ap-beijing-fsi.myqcloud.com' => lang('中国大陆 金融云地域 北京金融'),
'cos.ap-hongkong.myqcloud.com' => lang('亚太地区 公有云地域 中国香港'),
'cos.ap-singapore.myqcloud.com' => lang('亚太地区 公有云地域 新加坡'),
'cos.ap-mumbai.myqcloud.com' => lang('亚太地区 公有云地域 孟买'),
'cos.ap-jakarta.myqcloud.com' => lang('亚太地区 公有云地域 雅加达'),
'cos.ap-seoul.myqcloud.com' => lang('亚太地区 公有云地域 首尔'),
'cos.ap-bangkok.myqcloud.com' => lang('亚太地区 公有云地域 曼谷'),
'cos.ap-tokyo.myqcloud.com' => lang('亚太地区 公有云地域 东京'),
'cos.na-siliconvalley.myqcloud.com' => lang('北美地区 公有云地域 硅谷'),
'cos.na-ashburn.myqcloud.com' => lang('北美地区 公有云地域 弗吉尼亚'),
'cos.na-toronto.myqcloud.com' => lang('北美地区 公有云地域 多伦多'),
'cos.sa-saopaulo.myqcloud.com' => lang('北美地区 公有云地域 圣保罗'),
'cos.eu-frankfurt.myqcloud.com' => lang('欧洲地区 公有云地域 法兰克福'),
'cos.eu-moscow.myqcloud.com' => lang('欧洲地区 公有云地域 莫斯科'),
];
}
/**
* 初始化入口.
* @throws Exception
*/
protected function init()
{
@ -82,146 +240,9 @@ class TxcosStorage implements StorageInterface
}
/**
* 上传文件内容
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$data = $this->token($name) + ['key' => $name];
if (is_string($attname) && strlen($attname) > 0) {
$data['Content-Disposition'] = urlencode($attname);
}
$data['success_action_status'] = '200';
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
} else {
return [];
}
}
/**
* 读取文件内容
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, '204 No Content'));
}
/**
* 判断是否存在
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "https://{$this->bucket}.{$this->point}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $name),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname,$name)}";
}
/**
* 获取存储路径
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
* @return string
*/
public function upload(): string
{
$proc = $this->app->request->isSsl() ? 'https' : 'http';
return "{$proc}://{$this->bucket}.{$this->point}";
}
/**
* 生成上传令牌
* @param string $name 文件名称
* @param integer $expires 有效时间
* @param ?string $attname 下载名称
* @return array
*/
public function token(string $name, int $expires = 3600, ?string $attname = null): array
{
$startTimestamp = time();
$endTimestamp = $startTimestamp + $expires;
$keyTime = "{$startTimestamp};{$endTimestamp}";
$siteurl = $this->url($name, false, $attname);
$policy = json_encode([
'expiration' => date('Y-m-d\TH:i:s.000\Z', $endTimestamp),
'conditions' => [['q-ak' => $this->secretId], ['q-sign-time' => $keyTime], ['q-sign-algorithm' => 'sha1']],
]);
return [
'policy' => base64_encode($policy), 'q-ak' => $this->secretId,
'siteurl' => $siteurl, 'q-key-time' => $keyTime, 'q-sign-algorithm' => 'sha1',
'q-signature' => hash_hmac('sha1', sha1($policy), hash_hmac('sha1', $keyTime, $this->secretKey)),
];
}
/**
* 生成请求签名
* 生成请求签名.
* @param string $method 请求方式
* @param string $soruce 资源名称
* @return array
*/
private function _sign(string $method, string $soruce): array
{
@ -257,48 +278,17 @@ class TxcosStorage implements StorageInterface
// 8.生成签名
$signArray = [
'q-sign-algorithm' => 'sha1',
'q-ak' => $this->secretId,
'q-sign-time' => $keyTime,
'q-key-time' => $keyTime,
'q-header-list' => $headerList,
'q-ak' => $this->secretId,
'q-sign-time' => $keyTime,
'q-key-time' => $keyTime,
'q-header-list' => $headerList,
'q-url-param-list' => $urlParamList,
'q-signature' => $signature,
'q-signature' => $signature,
];
$header['Authorization'] = urldecode(http_build_query($signArray));
foreach ($header as $key => $value) $header[$key] = ucfirst($key) . ": {$value}";
foreach ($header as $key => $value) {
$header[$key] = ucfirst($key) . ": {$value}";
}
return array_values($header);
}
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
return [
'cos.ap-beijing-1.myqcloud.com' => lang('中国大陆 公有云地域 北京一区'),
'cos.ap-beijing.myqcloud.com' => lang('中国大陆 公有云地域 北京'),
'cos.ap-nanjing.myqcloud.com' => lang('中国大陆 公有云地域 南京'),
'cos.ap-shanghai.myqcloud.com' => lang('中国大陆 公有云地域 上海'),
'cos.ap-guangzhou.myqcloud.com' => lang('中国大陆 公有云地域 广州'),
'cos.ap-chengdu.myqcloud.com' => lang('中国大陆 公有云地域 成都'),
'cos.ap-chongqing.myqcloud.com' => lang('中国大陆 公有云地域 重庆'),
'cos.ap-shenzhen-fsi.myqcloud.com' => lang('中国大陆 金融云地域 深圳金融'),
'cos.ap-shanghai-fsi.myqcloud.com' => lang('中国大陆 金融云地域 上海金融'),
'cos.ap-beijing-fsi.myqcloud.com' => lang('中国大陆 金融云地域 北京金融'),
'cos.ap-hongkong.myqcloud.com' => lang('亚太地区 公有云地域 中国香港'),
'cos.ap-singapore.myqcloud.com' => lang('亚太地区 公有云地域 新加坡'),
'cos.ap-mumbai.myqcloud.com' => lang('亚太地区 公有云地域 孟买'),
'cos.ap-jakarta.myqcloud.com' => lang('亚太地区 公有云地域 雅加达'),
'cos.ap-seoul.myqcloud.com' => lang('亚太地区 公有云地域 首尔'),
'cos.ap-bangkok.myqcloud.com' => lang('亚太地区 公有云地域 曼谷'),
'cos.ap-tokyo.myqcloud.com' => lang('亚太地区 公有云地域 东京'),
'cos.na-siliconvalley.myqcloud.com' => lang('北美地区 公有云地域 硅谷'),
'cos.na-ashburn.myqcloud.com' => lang('北美地区 公有云地域 弗吉尼亚'),
'cos.na-toronto.myqcloud.com' => lang('北美地区 公有云地域 多伦多'),
'cos.sa-saopaulo.myqcloud.com' => lang('北美地区 公有云地域 圣保罗'),
'cos.eu-frankfurt.myqcloud.com' => lang('欧洲地区 公有云地域 法兰克福'),
'cos.eu-moscow.myqcloud.com' => lang('欧洲地区 公有云地域 莫斯科'),
];
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\storage;
@ -27,33 +29,169 @@ use think\admin\Storage;
/**
* 又拍云存储支持
* @class UpyunStorage
* @package think\admin\storage
*/
class UpyunStorage implements StorageInterface
{
use StorageUsageTrait;
/**
* 存储空间名称
* 存储空间名称.
* @var string
*/
private $bucket;
/**
* AccessId
* AccessId.
* @var string
*/
private $accessKey;
/**
* AccessSecret
* AccessSecret.
* @var string
*/
private $secretKey;
/**
* 初始化入口
* @throws \think\admin\Exception
* 上传文件内容.
* @param string $name 文件名称
* @param string $file 文件内容
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$data = [];
$token = $this->token($name, 3600, $attname, md5($file));
$data['policy'] = $token['policy'];
$data['authorization'] = $token['authorization'];
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
}
return [];
}
/**
* 读取文件内容.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "{$this->upload()}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 判断是否存在.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "{$this->upload()}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname, $name)}";
}
/**
* 获取存储路径.
* @param string $name 文件名称
* @param bool $safe 安全模式
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息.
* @param string $name 文件名称
* @param bool $safe 安全模式
* @param ?string $attname 下载名称
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
*/
public function upload(): string
{
$protocol = $this->app->request->isSsl() ? 'https' : 'http';
return "{$protocol}://v0.api.upyun.com/{$this->bucket}";
}
/**
* 生成上传令牌.
* @param string $name 文件名称
* @param int $expires 有效时间
* @param ?string $attname 下载名称
* @param ?string $fileHash 文件哈希
*/
public function token(string $name, int $expires = 3600, ?string $attname = null, ?string $fileHash = ''): array
{
$policy = ['save-key' => $name];
$policy['date'] = gmdate('D, d M Y H:i:s \G\M\T');
$policy['bucket'] = $this->bucket;
$policy['expiration'] = time() + $expires;
if ($fileHash) {
$policy['content-md5'] = $fileHash;
}
$data = ['keyid' => $this->accessKey, 'siteurl' => $this->url($name, false, $attname)];
$data['policy'] = base64_encode(json_encode($policy, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$content = "POST&/{$this->bucket}&{$policy['date']}&{$data['policy']}";
if ($fileHash) {
$content .= "&{$fileHash}";
}
$data['signature'] = base64_encode(hash_hmac('sha1', $content, md5($this->secretKey), true));
$data['authorization'] = "UPYUN {$this->accessKey}:{$data['signature']}";
return $data;
}
/**
* 获取存储区域
*/
public static function region(): array
{
return [];
}
/**
* 初始化入口.
* @throws Exception
*/
protected function init()
{
@ -74,145 +212,9 @@ class UpyunStorage implements StorageInterface
}
/**
* 上传文件内容
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function set(string $name, string $file, bool $safe = false, ?string $attname = null): array
{
$data = [];
$token = $this->token($name, 3600, $attname, md5($file));
$data['policy'] = $token['policy'];
$data['authorization'] = $token['authorization'];
$file = ['field' => 'file', 'name' => $name, 'content' => $file];
if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
} else {
return [];
}
}
/**
* 读取文件内容
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function get(string $name, bool $safe = false): string
{
return Storage::curlGet($this->url($name, $safe));
}
/**
* 删除存储文件
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function del(string $name, bool $safe = false): bool
{
[$file] = explode('?', $name);
$result = HttpExtend::request('DELETE', "{$this->upload()}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('DELETE', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 判断是否存在
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function has(string $name, bool $safe = false): bool
{
$file = $this->delSuffix($name);
$result = HttpExtend::request('HEAD', "{$this->upload()}/{$file}", [
'returnHeader' => true, 'headers' => $this->_sign('HEAD', $file),
]);
return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
}
/**
* 获取访问地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return string
*/
public function url(string $name, bool $safe = false, ?string $attname = null): string
{
return "{$this->domain}/{$this->delSuffix($name)}{$this->getSuffix($attname,$name)}";
}
/**
* 获取存储路径
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function path(string $name, bool $safe = false): string
{
return $this->url($name, $safe);
}
/**
* 获取文件信息
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param ?string $attname 下载名称
* @return array
*/
public function info(string $name, bool $safe = false, ?string $attname = null): array
{
return $this->has($name, $safe) ? [
'url' => $this->url($name, $safe, $attname),
'key' => $name, 'file' => $this->path($name, $safe),
] : [];
}
/**
* 获取上传地址
* @return string
*/
public function upload(): string
{
$protocol = $this->app->request->isSsl() ? 'https' : 'http';
return "{$protocol}://v0.api.upyun.com/{$this->bucket}";
}
/**
* 生成上传令牌
* @param string $name 文件名称
* @param integer $expires 有效时间
* @param ?string $attname 下载名称
* @param ?string $fileHash 文件哈希
* @return array
*/
public function token(string $name, int $expires = 3600, ?string $attname = null, ?string $fileHash = ''): array
{
$policy = ['save-key' => $name];
$policy['date'] = gmdate('D, d M Y H:i:s \G\M\T');
$policy['bucket'] = $this->bucket;
$policy['expiration'] = time() + $expires;
if ($fileHash) $policy['content-md5'] = $fileHash;
$data = ['keyid' => $this->accessKey, 'siteurl' => $this->url($name, false, $attname)];
$data['policy'] = base64_encode(json_encode($policy, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$content = "POST&/{$this->bucket}&{$policy['date']}&{$data['policy']}";
if ($fileHash) $content .= "&{$fileHash}";
$data['signature'] = base64_encode(hash_hmac('sha1', $content, md5($this->secretKey), true));
$data['authorization'] = "UPYUN {$this->accessKey}:{$data['signature']}";
return $data;
}
/**
* 生成请求签名
* 生成请求签名.
* @param string $method 请求方式
* @param string $name 资源名称
* @return array
*/
private function _sign(string $method, string $name): array
{
@ -220,13 +222,4 @@ class UpyunStorage implements StorageInterface
$signature = base64_encode(hash_hmac('sha1', join('&', $data), md5($this->secretKey), true));
return ["Authorization:UPYUN {$this->accessKey}:{$signature}", "Date:{$date}"];
}
/**
* 获取存储区域
* @return array
*/
public static function region(): array
{
return [];
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support;
@ -23,12 +25,11 @@ use think\Route as ThinkRoute;
/**
* 自定义路由对象
* @class Route
* @package think\admin\support
*/
class Route extends ThinkRoute
{
/**
* 重载路由配置
* 重载路由配置.
* @return $this
*/
public function reload(): Route
@ -36,4 +37,4 @@ class Route extends ThinkRoute
$this->config = array_merge($this->config, $this->app->config->get('route'));
return $this;
}
}
}

View File

@ -24,59 +24,37 @@
// 以下代码来自 topthink/think-multi-app有部分修改以兼容 ThinkAdmin 的需求
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support;
use InvalidArgumentException;
use think\admin\service\NodeService;
use think\route\Url as ThinkUrl;
/**
* 多应用 URL 生成与解析
* 多应用 URL 生成与解析.
* @class Url
* @package think\admin\support
*/
class Url extends ThinkUrl
{
/**
* 直接解析 URL 地址
* @param string $url URL
* @param string|boolean $domain Domain
* @return string
*/
protected function parseUrl(string $url, &$domain): string
{
$request = $this->app->request;
if (0 === strpos($url, '/')) {
$url = substr($url, 1);
} elseif (false !== strpos($url, '\\')) {
$url = ltrim(str_replace('\\', '/', $url), '/');
} elseif (0 === strpos($url, '@')) {
$url = substr($url, 1);
} else {
$attrs = str2arr($url, '/');
$action = empty($attrs) ? $request->action() : array_pop($attrs);
$contrl = empty($attrs) ? $request->controller() : array_pop($attrs);
$module = empty($attrs) ? $this->app->http->getName() : array_pop($attrs);
// 拼装新的链接地址
$url = NodeService::nameTolower($contrl) . '/' . $action;
$bind = $this->app->config->get('app.domain_bind', []);
if ($key = array_search($module, $bind)) {
if (isset($bind[$_SERVER['SERVER_NAME']])) $domain = $_SERVER['SERVER_NAME'];
$domain = is_bool($domain) ? $key : $domain;
} elseif ($key = array_search($module, $this->app->config->get('app.app_map', []))) {
$url = $key . '/' . $url;
} else {
$url = $module . '/' . $url;
}
}
return $url;
}
/**
* Build URL
* @return string
* Build URL.
*/
public function build(): string
{
@ -85,26 +63,26 @@ class Url extends ThinkUrl
$domain = $this->domain;
$suffix = $this->suffix;
$request = $this->app->request;
if (0 === strpos($url, '[') && $pos = strpos($url, ']')) {
if (strpos($url, '[') === 0 && $pos = strpos($url, ']')) {
// [name] 表示使用路由命名标识生成URL
$name = substr($url, 1, $pos - 1);
$url = 'name' . substr($url, $pos + 1);
}
if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {
if (strpos($url, '://') === false && strpos($url, '/') !== 0) {
$info = parse_url($url);
$url = !empty($info['path']) ? $info['path'] : '';
if (isset($info['fragment'])) {
// 解析锚点
$anchor = $info['fragment'];
if (false !== strpos($anchor, '?')) {
if (strpos($anchor, '?') !== false) {
// 解析参数
[$anchor, $info['query']] = explode('?', $anchor, 2);
}
if (false !== strpos($anchor, '@')) {
if (strpos($anchor, '@') !== false) {
// 解析域名
[$anchor, $domain] = explode('@', $anchor, 2);
}
} elseif (strpos($url, '@') && false === strpos($url, '\\')) {
} elseif (strpos($url, '@') && strpos($url, '\\') === false) {
// 解析域名
[$url, $domain] = explode('@', $url, 2);
}
@ -122,17 +100,21 @@ class Url extends ThinkUrl
}
if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars, $domain)) {
$url = $match[0];
if ($domain && !empty($match[1])) $domain = $match[1];
if (!is_null($match[2])) $suffix = $match[2];
if ($domain && !empty($match[1])) {
$domain = $match[1];
}
if (!is_null($match[2])) {
$suffix = $match[2];
}
if (!$this->app->http->isBind()) {
$url = $this->app->http->getName() . '/' . $url;
}
} elseif (!empty($rule) && isset($name)) {
throw new InvalidArgumentException('route name not exists:' . $name);
throw new \InvalidArgumentException('route name not exists:' . $name);
} else {
// 检测URL绑定
$bind = $this->route->getDomainBind($domain && is_string($domain) ? $domain : null);
if ($bind && 0 === strpos($url, $bind)) {
if ($bind && strpos($url, $bind) === 0) {
$url = substr($url, strlen($bind) + 1);
}
// 路由标识不存在 直接解析
@ -147,13 +129,13 @@ class Url extends ThinkUrl
$file = $request->baseFile();
$depr = $this->route->config('pathinfo_depr');
[$uri, $url] = [$request->url(), str_replace('/', $depr, $url)];
if ($file && 0 !== strpos($uri, $file)) {
if ($file && strpos($uri, $file) !== 0) {
$file = str_replace('\\', '/', dirname($file));
}
/*=====- 多应用绑定 URL 生成处理 -=====*/
/* =====- 多应用绑定 URL 生成处理 -===== */
$app = $this->app->http->getName();
if ($this->app->http->isBind()) {
if (preg_match("#^{$app}({$depr}|\.|$)#i", $url)) {
if (preg_match("#^{$app}({$depr}|\\.|$)#i", $url)) {
$url = trim(substr($url, strlen($app)), $depr);
} elseif (substr_count($url, $depr) >= 2) {
$file = 'index.php';
@ -161,7 +143,7 @@ class Url extends ThinkUrl
}
$url = rtrim($file, '/') . '/' . ltrim($url, '/');
// URL后缀
if ('/' == substr($url, -1) || '' == $url) {
if (substr($url, -1) == '/' || $url == '') {
$suffix = '';
} else {
$suffix = $this->parseSuffix($suffix);
@ -190,4 +172,40 @@ class Url extends ThinkUrl
// URL 组装
return $domain . rtrim($this->root, '/') . '/' . ltrim($url, '/');
}
}
/**
* 直接解析 URL 地址
* @param string $url URL
* @param bool|string $domain Domain
*/
protected function parseUrl(string $url, &$domain): string
{
$request = $this->app->request;
if (strpos($url, '/') === 0) {
$url = substr($url, 1);
} elseif (strpos($url, '\\') !== false) {
$url = ltrim(str_replace('\\', '/', $url), '/');
} elseif (strpos($url, '@') === 0) {
$url = substr($url, 1);
} else {
$attrs = str2arr($url, '/');
$action = empty($attrs) ? $request->action() : array_pop($attrs);
$contrl = empty($attrs) ? $request->controller() : array_pop($attrs);
$module = empty($attrs) ? $this->app->http->getName() : array_pop($attrs);
// 拼装新的链接地址
$url = NodeService::nameTolower($contrl) . '/' . $action;
$bind = $this->app->config->get('app.domain_bind', []);
if ($key = array_search($module, $bind)) {
if (isset($bind[$_SERVER['SERVER_NAME']])) {
$domain = $_SERVER['SERVER_NAME'];
}
$domain = is_bool($domain) ? $key : $domain;
} elseif ($key = array_search($module, $this->app->config->get('app.app_map', []))) {
$url = $key . '/' . $url;
} else {
$url = $module . '/' . $url;
}
}
return $url;
}
}

View File

@ -1,38 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
use think\admin\Command;
use think\admin\Exception;
use think\admin\service\SystemService;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
/**
* 数据库修复优化指令
* 数据库修复优化指令.
* @class Database
* @package think\admin\support\command
*/
class Database extends Command
{
/**
* 指令任务配置
* 指令任务配置.
*/
public function configure()
{
@ -42,30 +44,29 @@ class Database extends Command
}
/**
* 任务执行入口
* @param \think\console\Input $input
* @param \think\console\Output $output
* @return void
* @throws \think\admin\Exception
* 任务执行入口.
* @throws Exception
*/
protected function execute(Input $input, Output $output): void
{
if ($this->app->db->connect()->getConfig('type') === 'sqlite') {
$this->setQueueError("Sqlite 数据库不支持 REPAIR 和 OPTIMIZE 操作!");
$this->setQueueError('Sqlite 数据库不支持 REPAIR 和 OPTIMIZE 操作!');
}
$action = $input->getArgument('action');
if (method_exists($this, $method = "_{$action}")) $this->$method();
else $this->output->error('Wrong operation, currently allow repair|optimize');
if (method_exists($this, $method = "_{$action}")) {
$this->{$method}();
} else {
$this->output->error('Wrong operation, currently allow repair|optimize');
}
}
/**
* 修复所有数据表
* @return void
* @throws \think\admin\Exception
* 修复所有数据表.
* @throws Exception
*/
protected function _repair(): void
{
$this->setQueueProgress("正在获取需要修复的数据表", '0');
$this->setQueueProgress('正在获取需要修复的数据表', '0');
[$tables, $total, $count] = SystemService::getTables();
$this->setQueueProgress("总共需要修复 {$total} 张数据表", '0');
foreach ($tables as $table) {
@ -77,13 +78,12 @@ class Database extends Command
}
/**
* 优化所有数据表
* @return void
* @throws \think\admin\Exception
* 优化所有数据表.
* @throws Exception
*/
protected function _optimize(): void
{
$this->setQueueProgress("正在获取需要优化的数据表", '0');
$this->setQueueProgress('正在获取需要优化的数据表', '0');
[$tables, $total, $count] = SystemService::getTables();
$this->setQueueProgress("总共需要优化 {$total} 张数据表", '0');
foreach ($tables as $table) {
@ -93,4 +93,4 @@ class Database extends Command
}
$this->setQueueSuccess("已完成对 {$total} 张数据表优化操作");
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
@ -24,17 +26,18 @@ use think\admin\extend\PhinxExtend;
use think\admin\Library;
use think\admin\service\SystemService;
use think\console\input\Option;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 生成数据安装包
* 生成数据安装包.
* @class Package
* @package think\admin\support\command
*/
class Package extends Command
{
/**
* 系统指定配置
* @return void
* 系统指定配置.
*/
public function configure()
{
@ -47,9 +50,8 @@ class Package extends Command
}
/**
* 生成系统安装数据包
* @return void
* @throws \think\admin\Exception
* 生成系统安装数据包.
* @throws Exception
*/
public function handle()
{
@ -73,8 +75,7 @@ class Package extends Command
}
/**
* 创建数据表
* @return boolean
* 创建数据表.
* @throws \Exception
*/
private function createScheme(): bool
@ -87,7 +88,9 @@ class Package extends Command
[$tables] = SystemService::getTables();
} else {
$tables = Library::$sapp->config->get('phinx.tables', []);
if (empty($tables)) [$tables] = SystemService::getTables();
if (empty($tables)) {
[$tables] = SystemService::getTables();
}
}
// 去除忽略的数据表
@ -98,7 +101,9 @@ class Package extends Command
[$prefix, $groups] = ['', []];
foreach ($tables as $table) {
$attr = explode('_', $table);
if ($attr[0] === 'plugin') array_shift($attr);
if ($attr[0] === 'plugin') {
array_shift($attr);
}
if (empty($prefix) || $prefix !== $attr[0]) {
$prefix = $attr[0];
}
@ -121,12 +126,11 @@ class Package extends Command
}
/**
* 创建数据包
* @return boolean
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* 创建数据包.
* @throws Exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
private function createBackup(): bool
{
@ -142,7 +146,9 @@ class Package extends Command
// 去除忽略的数据表
$ignore = Library::$sapp->config->get('phinx.ignore', []);
if (empty($ignore)) $ignore = ['system_queue', 'system_oplog'];
if (empty($ignore)) {
$ignore = ['system_queue', 'system_oplog'];
}
$tables = array_unique(array_diff($tables, $ignore, ['migrations']));
// 创建数据库记录安装脚本
@ -152,9 +158,8 @@ class Package extends Command
if (file_put_contents($target, $phinx['text']) !== false) {
$this->setQueueMessage(4, 2, '成功创建数据包安装脚本!');
return true;
} else {
$this->setQueueMessage(4, 2, '创建数据包安装脚本失败!');
return false;
}
$this->setQueueMessage(4, 2, '创建数据包安装脚本失败!');
return false;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
@ -27,16 +29,13 @@ use think\console\input\Option;
use think\console\Output;
/**
* 组件安装指令
* 组件安装指令.
* @class Publish
* @package think\admin\support\command
*/
class Publish extends Command
{
/**
* 任务参数配置
* @return void
* 任务参数配置.
*/
public function configure()
{
@ -47,9 +46,7 @@ class Publish extends Command
}
/**
* 任务合并执行
* @param \think\console\Input $input
* @param \think\console\Output $output
* 任务合并执行.
* @return null|void
*/
public function execute(Input $input, Output $output)
@ -59,7 +56,7 @@ class Publish extends Command
}
/**
* 安装数据库
* 安装数据库.
* @return $this
*/
private function plugin(): Publish
@ -78,28 +75,27 @@ class Publish extends Command
}
/**
* 初始化组件文件
* 初始化组件文件.
* @param string $copy 应用资源目录
* @param boolean $force 是否强制替换
* @return void
* @param bool $force 是否强制替换
*/
private function copy(string $copy, bool $force = false)
{
// 复制系统配置文件
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'config';
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'config';
ToolsExtend::copy($frdir, syspath('config'), [], $force, false);
// 复制静态资料文件
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'public';
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'public';
ToolsExtend::copy($frdir, syspath('public'), [], true, false);
// 复制数据库脚本
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'database';
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'database';
ToolsExtend::copy($frdir, syspath('database/migrations'), [], $force, false);
}
/**
* 解析 json
* 解析 json .
* @return $this
*/
private function parse(): Publish
@ -112,16 +108,16 @@ class Publish extends Command
$type = $package['type'] ?? '';
$config = $package['extra']['config'] ?? [];
$versions[$package['name']] = [
'type' => $config['type'] ?? ($type === 'think-admin-plugin' ? 'plugin' : 'library'),
'name' => $config['name'] ?? ($package['name'] ?? ''),
'icon' => $config['icon'] ?? '',
'cover' => $config['cover'] ?? '',
'super' => $config['super'] ?? false,
'license' => (array)($config['license'] ?? ($package['license'] ?? [])),
'version' => $config['version'] ?? ($package['version'] ?? ''),
'homepage' => $config['homepage'] ?? ($package['homepage'] ?? ''),
'document' => $config['document'] ?? ($package['document'] ?? ''),
'platforms' => $config['platforms'] ?? [],
'type' => $config['type'] ?? ($type === 'think-admin-plugin' ? 'plugin' : 'library'),
'name' => $config['name'] ?? ($package['name'] ?? ''),
'icon' => $config['icon'] ?? '',
'cover' => $config['cover'] ?? '',
'super' => $config['super'] ?? false,
'license' => (array)($config['license'] ?? ($package['license'] ?? [])),
'version' => $config['version'] ?? ($package['version'] ?? ''),
'homepage' => $config['homepage'] ?? ($package['homepage'] ?? ''),
'document' => $config['document'] ?? ($package['document'] ?? ''),
'platforms' => $config['platforms'] ?? [],
'description' => $config['description'] ?? ($package['description'] ?? ''),
];
// 生成服务配置
@ -148,7 +144,7 @@ class Publish extends Command
}
// 写入服务配置
$header = "// Automatically Generated At: " . date('Y-m-d H:i:s') . PHP_EOL . 'declare(strict_types=1);';
$header = '// Automatically Generated At: ' . date('Y-m-d H:i:s') . PHP_EOL . 'declare(strict_types=1);';
$content = '<?php' . PHP_EOL . $header . PHP_EOL . 'return ' . var_export($services, true) . ';';
@file_put_contents(syspath('vendor/services.php'), $content);
@ -158,4 +154,4 @@ class Publish extends Command
return $this;
}
}
}

View File

@ -1,25 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
use Error;
use Exception;
use Psr\Log\NullLogger;
use think\admin\Command;
use think\admin\model\SystemQueue;
@ -28,54 +28,54 @@ use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use Throwable;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 异步任务管理指令
* 异步任务管理指令.
* @class Queue
* @package think\admin\support\command
*/
class Queue extends Command
{
/**
* 任务等待处理
* @var integer
* 任务等待处理.
* @var int
*/
const STATE_WAIT = 1;
public const STATE_WAIT = 1;
/**
* 任务正在处理
* @var integer
* 任务正在处理.
* @var int
*/
const STATE_LOCK = 2;
public const STATE_LOCK = 2;
/**
* 任务处理完成
* @var integer
* 任务处理完成.
* @var int
*/
const STATE_DONE = 3;
public const STATE_DONE = 3;
/**
* 任务处理失败
* @var integer
* 任务处理失败.
* @var int
*/
const STATE_ERROR = 4;
public const STATE_ERROR = 4;
/**
* 监听进程指令
* 监听进程指令.
* @var string
*/
const QUEUE_LISTEN = 'xadmin:queue listen';
public const QUEUE_LISTEN = 'xadmin:queue listen';
/**
* 当前任务编号
* 当前任务编号.
* @var string
*/
protected $code;
/**
* 指令任务配置
* 指令任务配置.
*/
public function configure()
{
@ -90,34 +90,35 @@ class Queue extends Command
}
/**
* 任务执行入口
* @param Input $input
* @param Output $output
* @return void
* 任务执行入口.
*/
protected function execute(Input $input, Output $output)
{
$action = $input->hasOption('daemon') ? 'start' : $input->getArgument('action');
if (method_exists($this, $method = "{$action}Action")) return $this->$method();
$this->output->error("># Wrong operation, Allow stop|start|status|query|listen|clean|dorun|webstop|webstart|webstatus");
if (method_exists($this, $method = "{$action}Action")) {
return $this->{$method}();
}
$this->output->error('># Wrong operation, Allow stop|start|status|query|listen|clean|dorun|webstop|webstart|webstatus');
}
/**
* 停止 WebServer 调试进程
* 停止 WebServer 调试进程.
*/
protected function webStopAction()
{
$root = syspath('public/');
if (count($result = $this->process->query("{$root} {$root}router.php")) < 1) {
$this->output->writeln("># There are no WebServer processes to stop");
} else foreach ($result as $item) {
$this->process->close(intval($item['pid']));
$this->output->writeln("># Successfully sent end signal to process {$item['pid']}");
$this->output->writeln('># There are no WebServer processes to stop');
} else {
foreach ($result as $item) {
$this->process->close(intval($item['pid']));
$this->output->writeln("># Successfully sent end signal to process {$item['pid']}");
}
}
}
/**
* 启动 WebServer 调试进程
* 启动 WebServer 调试进程.
*/
protected function webStartAction()
{
@ -128,13 +129,17 @@ class Queue extends Command
$command = "php -S {$host}:{$port} -t {$root} {$root}router.php";
$this->output->comment(">$ {$command}");
if (count($result = $this->process->query($command)) > 0) {
if ($this->process->isWin()) $this->process->exec("start {$prot}://{$host}:{$port}");
if ($this->process->isWin()) {
$this->process->exec("start {$prot}://{$host}:{$port}");
}
$this->output->writeln("># WebServer process already exist for pid {$result[0]['pid']}");
} else {
$this->process->create($command, 2000);
if (count($result = $this->process->query($command)) > 0) {
$this->output->writeln("># WebServer process started successfully for pid {$result[0]['pid']}");
if ($this->process->isWin()) $this->process->exec("start {$prot}://{$host}:{$port}");
if ($this->process->isWin()) {
$this->process->exec("start {$prot}://{$host}:{$port}");
}
} else {
$this->output->writeln('># WebServer process failed to start');
}
@ -142,7 +147,7 @@ class Queue extends Command
}
/**
* 查看 WebServer 调试进程
* 查看 WebServer 调试进程.
*/
protected function webStatusAction()
{
@ -151,7 +156,7 @@ class Queue extends Command
$this->output->comment(">$ {$result[0]['cmd']}");
$this->output->writeln("># WebServer process {$result[0]['pid']} running");
} else {
$this->output->writeln("># The WebServer process is not running");
$this->output->writeln('># The WebServer process is not running');
}
}
@ -161,18 +166,20 @@ class Queue extends Command
protected function stopAction()
{
if (count($result = $this->process->thinkQuery('xadmin:queue')) < 1) {
$this->output->writeln("># There are no task processes to stop");
} else foreach ($result as $item) {
$this->process->close(intval($item['pid']));
$this->output->writeln("># Successfully sent end signal to process {$item['pid']}");
$this->output->writeln('># There are no task processes to stop');
} else {
foreach ($result as $item) {
$this->process->close(intval($item['pid']));
$this->output->writeln("># Successfully sent end signal to process {$item['pid']}");
}
}
}
/**
* 启动后台任务
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function startAction()
{
@ -180,7 +187,7 @@ class Queue extends Command
$this->output->comment(">$ {$this->process->think(static::QUEUE_LISTEN)}");
if (count($result = $this->process->thinkQuery(static::QUEUE_LISTEN)) > 0) {
if (is_file($lock = syspath('runtime/cache/time.queue')) && intval(file_get_contents($lock)) + 60 < time()) {
$this->output->writeln("># The task monitoring delay has exceeded 60 seconds, and the monitoring will be restarted.");
$this->output->writeln('># The task monitoring delay has exceeded 60 seconds, and the monitoring will be restarted.');
$this->process->close(intval($result[0]['pid'])) && $this->process->thinkExec(static::QUEUE_LISTEN, 1000);
} else {
$this->output->writeln("># Queue daemons already exist for pid {$result[0]['pid']}");
@ -190,7 +197,7 @@ class Queue extends Command
if (count($result = $this->process->thinkQuery(static::QUEUE_LISTEN)) > 0) {
$this->output->writeln("># Queue daemons started successfully for pid {$result[0]['pid']}");
} else {
$this->output->writeln("># Queue daemons failed to start");
$this->output->writeln('># Queue daemons failed to start');
}
}
}
@ -201,8 +208,10 @@ class Queue extends Command
protected function queryAction()
{
$items = $this->process->thinkQuery('xadmin:queue');
if (count($items) > 0) foreach ($items as $item) {
$this->output->writeln("># {$item['pid']}\t{$item['cmd']}");
if (count($items) > 0) {
foreach ($items as $item) {
$this->output->writeln("># {$item['pid']}\t{$item['cmd']}");
}
} else {
$this->output->writeln('># No related task process found');
}
@ -211,7 +220,7 @@ class Queue extends Command
/**
* 清理所有任务
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
* @throws DbException
*/
protected function cleanAction()
{
@ -244,13 +253,12 @@ class Queue extends Command
if (count($result = $this->process->thinkQuery(static::QUEUE_LISTEN)) > 0) {
$this->output->writeln("Listening for main process {$result[0]['pid']} running");
} else {
$this->output->writeln("The Listening main process is not running");
$this->output->writeln('The Listening main process is not running');
}
}
/**
* 启动任务监听
* @return void
* 启动任务监听.
*/
protected function listenAction()
{
@ -258,7 +266,7 @@ class Queue extends Command
set_time_limit(0) && PHP_SAPI !== 'cli' && ignore_user_abort(true);
$this->app->db->setLog(new NullLogger());
$this->createListenProcess();
} catch (Exception $exception) {
} catch (\Exception $exception) {
trace_file($exception) && usleep(3000000);
$this->output->write('=============== EXCEPTION ===============');
$this->output->write($exception->getMessage());
@ -268,8 +276,56 @@ class Queue extends Command
}
/**
* 执行任务监听
* @return void
* 执行指定任务
* @throws \think\admin\Exception
*/
protected function doRunAction()
{
$this->code = trim($this->input->getArgument('code'));
if (empty($this->code)) {
$this->output->error('Task number needs to be specified for task execution');
} else {
try {
set_time_limit(0) && PHP_SAPI !== 'cli' && ignore_user_abort(true);
$this->queue->initialize($this->code);
if (empty($this->queue->record) || intval($this->queue->record->getAttr('status')) !== static::STATE_WAIT) {
// 这里不做任何处理(该任务可能在其它地方已经在执行)
$this->output->warning("The or status of task {$this->code} is abnormal");
} else {
// 锁定任务状态,防止任务再次被执行
SystemQueue::mk()->strict(false)->where(['code' => $this->code])->inc('attempts')->update([
'enter_time' => microtime(true), 'outer_time' => 0, 'exec_pid' => getmypid(), 'exec_desc' => '', 'status' => static::STATE_LOCK,
]);
$this->queue->progress(2, '>>> 任务处理开始 <<<', '0');
// 执行任务内容
defined('WorkQueueCall') or define('WorkQueueCall', true);
defined('WorkQueueCode') or define('WorkQueueCode', $this->code);
if (class_exists($command = $this->queue->record->getAttr('command'))) {
// 自定义任务,支持返回消息(支持异常结束,异常码可选择 3|4 设置任务状态)
/* @var \think\admin\Queue|QueueService $class */
$class = $this->app->make($command, [], true);
if ($class instanceof \think\admin\Queue) {
$this->updateQueue(static::STATE_DONE, $class->initialize($this->queue)->execute($this->queue->data) ?: '');
} elseif ($class instanceof QueueService) {
$this->updateQueue(static::STATE_DONE, $class->initialize($this->queue->code)->execute($this->queue->data) ?: '');
} else {
throw new \think\admin\Exception("自定义 {$command} 未继承 think\\admin\\Queue 或 think\\admin\\service\\QueueService");
}
} else {
// 自定义指令,不支持返回消息(支持异常结束,异常码可选择 3|4 设置任务状态)
$attr = explode(' ', trim(preg_replace('|\s+|', ' ', $command)));
$this->updateQueue(static::STATE_DONE, $this->app->console->call(array_shift($attr), $attr)->fetch(), false);
}
}
} catch (\Error|\Exception|\Throwable $exception) {
$isDone = intval($exception->getCode()) === static::STATE_DONE;
$this->updateQueue($isDone ? static::STATE_DONE : static::STATE_ERROR, $exception->getMessage());
}
}
}
/**
* 执行任务监听.
*/
private function createListenProcess()
{
@ -278,76 +334,32 @@ class Queue extends Command
while (true) {
@file_put_contents(syspath('runtime/cache/time.queue'), strval(time()));
[$map, $start] = [[['status', '=', static::STATE_WAIT], ['exec_time', '<=', time()]], microtime(true)];
foreach (SystemQueue::mk()->where($map)->order('exec_time asc')->cursor() as $queue) try {
$args = "xadmin:queue dorun {$queue['code']} -";
$this->output->comment(">$ {$this->process->think($args)}");
if (count($this->process->thinkQuery($args)) > 0) {
$this->output->writeln("># Already in progress -> [{$queue['code']}] {$queue['title']}");
} else {
$this->process->thinkExec($args);
$this->output->writeln("># Created new process -> [{$queue['code']}] {$queue['title']}");
}
} catch (Exception $exception) {
$queue->save(['status' => static::STATE_ERROR, 'outer_time' => time(), 'exec_desc' => $exception->getMessage()]);
$this->output->error("># Execution failed -> [{$queue['code']}] {$queue['title']}{$exception->getMessage()}");
}
if (microtime(true) < $start + 1) usleep(1000000);
}
}
/**
* 执行指定任务
* @return void
* @throws \think\admin\Exception
*/
protected function doRunAction()
{
$this->code = trim($this->input->getArgument('code'));
if (empty($this->code)) {
$this->output->error('Task number needs to be specified for task execution');
} else try {
set_time_limit(0) && PHP_SAPI !== 'cli' && ignore_user_abort(true);
$this->queue->initialize($this->code);
if (empty($this->queue->record) || intval($this->queue->record->getAttr('status')) !== static::STATE_WAIT) {
// 这里不做任何处理(该任务可能在其它地方已经在执行)
$this->output->warning("The or status of task {$this->code} is abnormal");
} else {
// 锁定任务状态,防止任务再次被执行
SystemQueue::mk()->strict(false)->where(['code' => $this->code])->inc('attempts')->update([
'enter_time' => microtime(true), 'outer_time' => 0, 'exec_pid' => getmypid(), 'exec_desc' => '', 'status' => static::STATE_LOCK,
]);
$this->queue->progress(2, '>>> 任务处理开始 <<<', '0');
// 执行任务内容
defined('WorkQueueCall') or define('WorkQueueCall', true);
defined('WorkQueueCode') or define('WorkQueueCode', $this->code);
if (class_exists($command = $this->queue->record->getAttr('command'))) {
// 自定义任务,支持返回消息(支持异常结束,异常码可选择 3|4 设置任务状态)
/**@var \think\admin\Queue|QueueService $class */
$class = $this->app->make($command, [], true);
if ($class instanceof \think\admin\Queue) {
$this->updateQueue(static::STATE_DONE, $class->initialize($this->queue)->execute($this->queue->data) ?: '');
} elseif ($class instanceof QueueService) {
$this->updateQueue(static::STATE_DONE, $class->initialize($this->queue->code)->execute($this->queue->data) ?: '');
foreach (SystemQueue::mk()->where($map)->order('exec_time asc')->cursor() as $queue) {
try {
$args = "xadmin:queue dorun {$queue['code']} -";
$this->output->comment(">$ {$this->process->think($args)}");
if (count($this->process->thinkQuery($args)) > 0) {
$this->output->writeln("># Already in progress -> [{$queue['code']}] {$queue['title']}");
} else {
throw new \think\admin\Exception("自定义 {$command} 未继承 think\admin\Queue 或 think\admin\service\QueueService");
$this->process->thinkExec($args);
$this->output->writeln("># Created new process -> [{$queue['code']}] {$queue['title']}");
}
} else {
// 自定义指令,不支持返回消息(支持异常结束,异常码可选择 3|4 设置任务状态)
$attr = explode(' ', trim(preg_replace('|\s+|', ' ', $command)));
$this->updateQueue(static::STATE_DONE, $this->app->console->call(array_shift($attr), $attr)->fetch(), false);
} catch (\Exception $exception) {
$queue->save(['status' => static::STATE_ERROR, 'outer_time' => time(), 'exec_desc' => $exception->getMessage()]);
$this->output->error("># Execution failed -> [{$queue['code']}] {$queue['title']}{$exception->getMessage()}");
}
}
} catch (Exception|Throwable|Error $exception) {
$isDone = intval($exception->getCode()) === static::STATE_DONE;
$this->updateQueue($isDone ? static::STATE_DONE : static::STATE_ERROR, $exception->getMessage());
if (microtime(true) < $start + 1) {
usleep(1000000);
}
}
}
/**
* 修改当前任务状态
* @param integer $status 任务状态
* @param int $status 任务状态
* @param string $message 消息内容
* @param boolean $isSplit 是否分隔
* @param bool $isSplit 是否分隔
* @throws \think\admin\Exception
*/
private function updateQueue(int $status, string $message, bool $isSplit = true)
@ -369,10 +381,12 @@ class Queue extends Command
$this->queue->progress($status, '>>> 任务处理失败 <<<');
}
// 注册循环任务
if (($time = intval($this->queue->record->getAttr('loops_time'))) > 0) try {
$this->queue->initialize($this->code)->reset($time);
} catch (Exception|Throwable|Error $exception) {
$this->app->log->error("Queue {$this->queue->record->getAttr('code')} Loops Failed. {$exception->getMessage()}");
if (($time = intval($this->queue->record->getAttr('loops_time'))) > 0) {
try {
$this->queue->initialize($this->code)->reset($time);
} catch (\Error|\Exception|\Throwable $exception) {
$this->app->log->error("Queue {$this->queue->record->getAttr('code')} Loops Failed. {$exception->getMessage()}");
}
}
}
}
}

View File

@ -1,39 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
use think\admin\Command;
use think\admin\Exception;
use think\admin\service\SystemService;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\db\exception\DbException;
use think\helper\Str;
/**
* 数据库字符替换
* 数据库字符替换.
* @class Replace
* @package think\admin\support\command
*/
class Replace extends Command
{
/**
* 指令任务配置
* 指令任务配置.
*/
protected function configure()
{
@ -44,23 +47,24 @@ class Replace extends Command
}
/**
* 任务执行入口
* @param \think\console\Input $input
* @param \think\console\Output $output
* @return void
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
* 任务执行入口.
* @throws Exception
* @throws DbException
*/
protected function execute(Input $input, Output $output)
{
$search = $input->getArgument('search');
$repalce = $input->getArgument('replace');
if ($search === '') $this->setQueueError('查找替换字符内容不能为空!');
if ($repalce === '') $this->setQueueError('目标替换字符内容不能为空!');
if ($search === '') {
$this->setQueueError('查找替换字符内容不能为空!');
}
if ($repalce === '') {
$this->setQueueError('目标替换字符内容不能为空!');
}
[$tables, $total, $count] = SystemService::getTables();
foreach ($tables as $table) {
$data = [];
$this->setQueueMessage($total, ++$count, sprintf("准备替换数据表 %s", Str::studly($table)));
$this->setQueueMessage($total, ++$count, sprintf('准备替换数据表 %s', Str::studly($table)));
foreach ($this->app->db->table($table)->getFields() as $field => $attrs) {
if (preg_match('/char|text/', $attrs['type'])) {
$data[$field] = $this->app->db->raw(sprintf('REPLACE(`%s`,"%s","%s")', $field, $search, $repalce));
@ -68,11 +72,11 @@ class Replace extends Command
}
if (count($data) > 0) {
$this->app->db->table($table)->master()->where('1=1')->update($data);
$this->setQueueMessage($total, $count, sprintf("成功替换数据表 %s", Str::studly($table)), 1);
$this->setQueueMessage($total, $count, sprintf('成功替换数据表 %s', Str::studly($table)), 1);
} else {
$this->setQueueMessage($total, $count, sprintf("无需替换数据表 %s", Str::studly($table)), 1);
$this->setQueueMessage($total, $count, sprintf('无需替换数据表 %s', Str::studly($table)), 1);
}
}
$this->setQueueSuccess("批量替换 {$total} 张数据表成功");
}
}
}

View File

@ -1,36 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
use think\admin\Command;
use think\admin\Exception;
use think\admin\extend\DataExtend;
use think\admin\model\SystemMenu;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 重置并清理系统菜单
* 重置并清理系统菜单.
* @class Sysmenu
* @package think\admin\support\command
*/
class Sysmenu extends Command
{
/**
* 指令任务配置
* 指令任务配置.
*/
public function configure()
{
@ -39,12 +44,11 @@ class Sysmenu extends Command
}
/**
* 任务执行入口
* @return void
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* 任务执行入口.
* @throws Exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function handle()
{
@ -55,20 +59,24 @@ class Sysmenu extends Command
foreach (DataExtend::arr2tree($menus) as $sub1) {
$pid1 = $this->write($sub1);
$this->setQueueMessage($total, ++$count, "重写1级菜单{$sub1['title']}");
if (!empty($sub1['sub'])) foreach ($sub1['sub'] as $sub2) {
$pid2 = $this->write($sub2, $pid1);
$this->setQueueMessage($total, ++$count, "重写2级菜单-> {$sub2['title']}");
if (!empty($sub2['sub'])) foreach ($sub2['sub'] as $sub3) {
$this->write($sub3, $pid2);
$this->setQueueMessage($total, ++$count, "重写3级菜单-> -> {$sub3['title']}");
if (!empty($sub1['sub'])) {
foreach ($sub1['sub'] as $sub2) {
$pid2 = $this->write($sub2, $pid1);
$this->setQueueMessage($total, ++$count, "重写2级菜单-> {$sub2['title']}");
if (!empty($sub2['sub'])) {
foreach ($sub2['sub'] as $sub3) {
$this->write($sub3, $pid2);
$this->setQueueMessage($total, ++$count, "重写3级菜单-> -> {$sub3['title']}");
}
}
}
}
}
$this->setQueueMessage($total, $count, "完成重置系统菜单编号!");
$this->setQueueMessage($total, $count, '完成重置系统菜单编号!');
}
/**
* 写入单项菜单数据
* 写入单项菜单数据.
* @param array $arr 单项菜单数据
* @param mixed $pid 上级菜单编号
* @return int|string
@ -76,13 +84,13 @@ class Sysmenu extends Command
private function write(array $arr, $pid = 0)
{
return SystemMenu::mk()->insertGetId([
'pid' => $pid,
'url' => $arr['url'],
'icon' => $arr['icon'],
'node' => $arr['node'],
'title' => $arr['title'],
'pid' => $pid,
'url' => $arr['url'],
'icon' => $arr['icon'],
'node' => $arr['node'],
'title' => $arr['title'],
'params' => $arr['params'],
'target' => $arr['target'],
]);
}
}
}

View File

@ -1,53 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\middleware;
use Closure;
use think\admin\Exception;
use think\admin\extend\JwtExtend;
use think\App;
use think\exception\HttpResponseException;
use think\Request;
use think\Response;
use think\Session;
/**
* 兼容会话中间键
* 兼容会话中间键.
* @class JwtSession
* @package think\admin\support\middleware
*/
class JwtSession
{
/**
* 当前 App 对象
* @var \think\App
* @var App
*/
protected $app;
/**
* 当前 Session 对象
* @var \think\Session
* @var Session
*/
protected $session;
/**
* Construct
* @param \think\App $app
* Construct.
*/
public function __construct(App $app)
{
@ -56,23 +56,22 @@ class JwtSession
}
/**
* 中间键处理
* @param \think\Request $request
* @param \Closure $next
* @return \think\Response
* 中间键处理.
*/
public function handle(Request $request, Closure $next): Response
public function handle(Request $request, \Closure $next): Response
{
// 处理 Jwt 请求,请求头存在 jwt-token 字段
if (($token = $request->header('jwt-token', ''))) try {
if (preg_match('#^\s*([\w\-]+\.[\w\-]+\.[\w\-]+)\s*$#', $token, $match)) {
JwtExtend::verify($match[1]);
$sessionId = JwtExtend::$sessionId;
} else {
throw new Exception('令牌格式错误!', 401);
if ($token = $request->header('jwt-token', '')) {
try {
if (preg_match('#^\s*([\w\-]+\.[\w\-]+\.[\w\-]+)\s*$#', $token, $match)) {
JwtExtend::verify($match[1]);
$sessionId = JwtExtend::$sessionId;
} else {
throw new Exception('令牌格式错误!', 401);
}
} catch (\Exception $exception) {
throw new HttpResponseException(json(['code' => $exception->getCode(), 'info' => lang($exception->getMessage())]));
}
} catch (\Exception $exception) {
throw new HttpResponseException(json(['code' => $exception->getCode(), 'info' => lang($exception->getMessage())]));
}
if (empty($sessionId)) {
@ -102,12 +101,11 @@ class JwtSession
}
/**
* 保存会话数据
* @return void
* 保存会话数据.
*/
public function end()
{
$this->session->save();
JwtExtend::$sessionId = '';
}
}
}

View File

@ -1,25 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\middleware;
use Closure;
use SplFileInfo;
use think\admin\extend\ToolsExtend;
use think\admin\Library;
use think\admin\Plugin;
@ -31,33 +31,31 @@ use think\Request;
use think\Response;
/**
* 多应用调度中间键
* 多应用调度中间键.
* @class MultAccess
* @package think\admin\support\middleware
*/
class MultAccess
{
/**
* 应用实例
* 应用实例.
* @var App
*/
private $app;
/**
* 应用路径
* 应用路径.
* @var string
*/
private $appPath;
/**
* 应用空间
* 应用空间.
* @var string
*/
private $appSpace;
/**
* App constructor.
* @param App $app
*/
public function __construct(App $app)
{
@ -65,70 +63,73 @@ class MultAccess
}
/**
* 多应用解析
* @param Request $request
* @param Closure $next
* @return Response
* 多应用解析.
*/
public function handle(Request $request, Closure $next): Response
public function handle(Request $request, \Closure $next): Response
{
[$this->appPath, $this->appSpace] = ['', ''];
if (!$this->parseMultiApp()) return $next($request);
if (!$this->parseMultiApp()) {
return $next($request);
}
return $this->app->middleware->pipeline('app')->send($request)->then(function ($request) use ($next) {
return $next($request);
});
}
/**
* 解析多应用
* @return bool
* 解析多应用.
*/
private function parseMultiApp(): bool
{
$defaultApp = $this->app->config->get('route.default_app') ?: 'index';
[$script, $pathinfo] = [$this->scriptName(), $this->app->request->pathinfo()];
if ($script && !in_array($script, ['index', 'router', 'think'])) {
$this->app->request->setPathinfo(preg_replace("#^{$script}\.php(/|\.|$)#i", '', $pathinfo) ?: '/');
$this->app->request->setPathinfo(preg_replace("#^{$script}\\.php(/|\\.|$)#i", '', $pathinfo) ?: '/');
return $this->setMultiApp($script, true);
} else {
// 域名绑定处理
$domains = $this->app->config->get('app.domain_bind', []);
if (!empty($domains)) foreach ([$this->app->request->host(true), $this->app->request->subDomain(), '*'] as $key) {
if (isset($domains[$key])) return $this->setMultiApp($domains[$key], true);
}
$name = current(explode('/', $pathinfo));
if (strpos($name, '.')) $name = strstr($name, '.', true);
// 应用绑定与插件处理
$addons = Plugin::get();
$appmap = $this->app->config->get('app.app_map', []);
if (isset($appmap[$name])) {
$appName = $appmap[$name] instanceof Closure ? (call_user_func_array($appmap[$name], [$this->app]) ?: $name) : $appmap[$name];
} elseif ($name && (in_array($name, $appmap) || in_array($name, $this->app->config->get('app.deny_app_list', [])))) {
throw new HttpException(404, "app not exists: {$name}");
} elseif ($name && isset($appmap['*'])) {
$appName = $appmap['*'];
} else {
$appName = $name ?: $defaultApp;
if (!isset($addons[$appName]) && !is_dir($this->app->getBasePath() . $appName)) {
return $this->app->config->get('app.app_express', false) && $this->setMultiApp($defaultApp, false);
}
// 域名绑定处理
$domains = $this->app->config->get('app.domain_bind', []);
if (!empty($domains)) {
foreach ([$this->app->request->host(true), $this->app->request->subDomain(), '*'] as $key) {
if (isset($domains[$key])) {
return $this->setMultiApp($domains[$key], true);
}
}
// 插件绑定处理
if (isset($addons[$appName])) {
[$this->appPath, $this->appSpace] = [$addons[$appName]['path'], $addons[$appName]['space']];
}
if ($name) {
$this->app->request->setRoot('/' . $name);
$this->app->request->setPathinfo(strpos($pathinfo, '/') ? ltrim(strstr($pathinfo, '/'), '/') : '');
}
$name = current(explode('/', $pathinfo));
if (strpos($name, '.')) {
$name = strstr($name, '.', true);
}
// 应用绑定与插件处理
$addons = Plugin::get();
$appmap = $this->app->config->get('app.app_map', []);
if (isset($appmap[$name])) {
$appName = $appmap[$name] instanceof \Closure ? (call_user_func_array($appmap[$name], [$this->app]) ?: $name) : $appmap[$name];
} elseif ($name && (in_array($name, $appmap) || in_array($name, $this->app->config->get('app.deny_app_list', [])))) {
throw new HttpException(404, "app not exists: {$name}");
} elseif ($name && isset($appmap['*'])) {
$appName = $appmap['*'];
} else {
$appName = $name ?: $defaultApp;
if (!isset($addons[$appName]) && !is_dir($this->app->getBasePath() . $appName)) {
return $this->app->config->get('app.app_express', false) && $this->setMultiApp($defaultApp, false);
}
}
// 插件绑定处理
if (isset($addons[$appName])) {
[$this->appPath, $this->appSpace] = [$addons[$appName]['path'], $addons[$appName]['space']];
}
if ($name) {
$this->app->request->setRoot('/' . $name);
$this->app->request->setPathinfo(strpos($pathinfo, '/') ? ltrim(strstr($pathinfo, '/'), '/') : '');
}
return $this->setMultiApp($appName ?? $defaultApp, $this->app->http->isBind());
}
/**
* 获取当前运行入口名称
* 获取当前运行入口名称.
* @codeCoverageIgnore
* @return string
*/
private function scriptName(): string
{
@ -137,10 +138,9 @@ class MultAccess
}
/**
* 设置应用参数
* 设置应用参数.
* @param string $appName 应用名称
* @param boolean $appBind 应用绑定
* @return boolean
* @param bool $appBind 应用绑定
*/
private function setMultiApp(string $appName, bool $appBind): bool
{
@ -154,24 +154,24 @@ class MultAccess
$this->app->config->set(['view_path' => $this->appPath . 'view' . DIRECTORY_SEPARATOR, 'tpl_replace_string' => $uris], 'view');
// 初始化多应用文件
return $this->loadMultiApp($this->appPath);
} else {
return false;
}
return false;
}
/**
* 加载应用文件
* 加载应用文件.
* @param string $appPath 应用路径
* @codeCoverageIgnore
* @return boolean
*/
private function loadMultiApp(string $appPath): bool
{
[$ext, $fmaps] = [$this->app->getConfigExt(), []];
// 加载应用函数文件
if (is_file($file = "{$appPath}common{$ext}")) Library::load($file);
if (is_file($file = "{$appPath}common{$ext}")) {
Library::load($file);
}
// 加载应用配置文件
ToolsExtend::find($appPath . 'config', 1, function (SplFileInfo $info) use ($ext) {
ToolsExtend::find($appPath . 'config', 1, function (\SplFileInfo $info) use ($ext) {
if ($info->isFile() && strtolower(".{$info->getExtension()}") === $ext) {
$this->app->config->load($info->getPathname(), $info->getBasename($ext));
}
@ -198,4 +198,4 @@ class MultAccess
}
return true;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\middleware;
@ -25,21 +27,19 @@ use think\Request;
use think\Response;
/**
* 后台权限中间键
* 后台权限中间键.
* @class RbacAccess
* @package think\admin\support\middleware
*/
class RbacAccess
{
/**
* 当前 App 对象
* @var \think\App
* @var App
*/
protected $app;
/**
* Construct
* @param \think\App $app
* Construct.
*/
public function __construct(App $app)
{
@ -47,10 +47,7 @@ class RbacAccess
}
/**
* 中间键处理
* @param \think\Request $request
* @param \Closure $next
* @return \think\Response
* 中间键处理.
*/
public function handle(Request $request, \Closure $next): Response
{
@ -81,4 +78,4 @@ class RbacAccess
$loginPage = preg_match('#^(/|https?://)#', $loginUrl) ? $loginUrl : sysuri($loginUrl);
throw new HttpResponseException(json(['code' => 0, 'info' => lang('请重新登录!'), 'url' => $loginPage]));
}
}
}

View File

@ -1,10 +1,32 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\tests;
use PHPUnit\Framework\TestCase;
use think\admin\extend\CodeExtend;
/**
* @internal
* @coversNothing
*/
class CodeTest extends TestCase
{
public function testUuidCreate()
@ -19,4 +41,4 @@ class CodeTest extends TestCase
$encode = CodeExtend::encrypt($value, 'thinkadmin');
$this->assertEquals($value, CodeExtend::decrypt($encode, 'thinkadmin'), '验证加密解密');
}
}
}

View File

@ -1,10 +1,32 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\tests;
use PHPUnit\Framework\TestCase;
use think\admin\extend\JwtExtend;
/**
* @internal
* @coversNothing
*/
class JwtTest extends TestCase
{
public function testJwtCreateAndVerify()
@ -15,4 +37,4 @@ class JwtTest extends TestCase
$result = JwtExtend::verify($token, $jwtkey);
$this->assertEquals($testdata['user'], $result['user']);
}
}
}

View File

@ -1,14 +1,36 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\tests;
use PHPUnit\Framework\TestCase;
use think\admin\model\SystemUser;
/**
* @internal
* @coversNothing
*/
class ModelTest extends TestCase
{
public function testVirtualModel()
{
$this->assertEquals(m('SystemUser')->getTable(), SystemUser::mk()->getTable(), '动态模型测试');
}
}
}

View File

@ -1,19 +1,41 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\tests;
use PHPUnit\Framework\TestCase;
/**
* @internal
* @coversNothing
*/
class StorageTest extends TestCase
{
public function testInit()
{
$this->assertEquals(1, 1);
}
// public function testAlist()
// {
// $alist = AlistStorage::instance();
// $alist->set('test.tt', $content = uniqid());
// $this->assertEquals($alist->get('test.tt'), $content);
// }
}
// public function testAlist()
// {
// $alist = AlistStorage::instance();
// $alist->set('test.tt', $content = uniqid());
// $this->assertEquals($alist->get('test.tt'), $content);
// }
}

View File

@ -1,22 +1,39 @@
<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
use think\facade\Db;
include_once dirname(__DIR__) . '/vendor/autoload.php';
include_once dirname(__DIR__) . '/vendor/topthink/framework/src/helper.php';
Db::setConfig([
'default' => 'mysql',
'default' => 'mysql',
'connections' => [
'mysql' => [
'type' => 'mysql',
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'admin_v6',
'username' => 'admin_v6',
'password' => 'FbYBHcWKr2',
'hostport' => '3306',
'charset' => 'utf8mb4',
'debug' => true,
'charset' => 'utf8mb4',
'debug' => true,
],
],
]);
]);

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account;
@ -23,24 +25,23 @@ use think\admin\Plugin;
/**
* 插件注册服务
* @class Service
* @package plugin\account
*/
class Service extends Plugin
{
/**
* 定义插件名称
* 定义插件名称.
* @var string
*/
protected $appName = '账号管理';
/**
* 定义安装包名
* 定义安装包名.
* @var string
*/
protected $package = 'zoujingli/think-plugs-account';
/**
* 定义插件菜单
* 定义插件菜单.
* @return array[]
*/
public static function menu(): array
@ -57,4 +58,4 @@ class Service extends Plugin
],
];
}
}
}

View File

@ -1,42 +1,47 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller;
use plugin\account\model\PluginAccountBind;
use plugin\account\service\Account;
use think\admin\Controller;
use think\admin\Exception;
use think\admin\helper\QueryHelper;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 终端账号管理
* 终端账号管理.
* @class Device
* @package plugin\account\controller\user
*/
class Device extends Controller
{
/**
* 终端账号管理
* 终端账号管理.
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index()
{
@ -51,10 +56,9 @@ class Device extends Controller
}
/**
* 账号接口配置
* 账号接口配置.
* @auth true
* @return void
* @throws \think\admin\Exception
* @throws Exception
*/
public function config()
{
@ -90,17 +94,17 @@ class Device extends Controller
public function state()
{
PluginAccountBind::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除终端账号
* 删除终端账号.
* @auth true
*/
public function remove()
{
PluginAccountBind::mDelete();
}
}
}

View File

@ -1,41 +1,45 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller;
use plugin\account\model\PluginAccountUser;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 用户账号管理
* 用户账号管理.
* @class Master
* @package plugin\account\controller\user
*/
class Master extends Controller
{
/**
* 用户账号管理
* 用户账号管理.
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index()
{
@ -55,17 +59,17 @@ class Master extends Controller
public function state()
{
PluginAccountUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除主账号
* 删除主账号.
* @auth true
*/
public function remove()
{
PluginAccountUser::mDelete();
}
}
}

View File

@ -1,61 +1,54 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller;
use plugin\account\model\PluginAccountMsms;
use plugin\account\service\Message as MessageService;
use plugin\account\service\message\Alisms;
use plugin\account\service\Message as MessageService;
use think\admin\Controller;
use think\admin\Exception;
use think\admin\helper\QueryHelper;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 手机短信管理
* 手机短信管理.
* @class Message
* @package plugin\account\controller
*/
class Message extends Controller
{
/**
* 缓存配置名称
* 缓存配置名称.
* @var string
*/
protected $smskey;
/**
* 初始化控制器
* @return void
*/
protected function initialize()
{
parent::initialize();
$this->smskey = 'plugin.account.smscfg';
}
/**
* 手机短信管理
* 手机短信管理.
* @auth true
* @menu true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index()
{
@ -68,10 +61,9 @@ class Message extends Controller
}
/**
* 修改短信配置
* 修改短信配置.
* @auth true
* @return void
* @throws \think\admin\Exception
* @throws Exception
*/
public function config()
{
@ -85,4 +77,13 @@ class Message extends Controller
$this->success('修改配置成功!');
}
}
}
/**
* 初始化控制器.
*/
protected function initialize()
{
parent::initialize();
$this->smskey = 'plugin.account.smscfg';
}
}

View File

@ -1,61 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller\api;
use plugin\account\service\Account;
use plugin\account\service\contract\AccountInterface;
use think\admin\Controller;
use think\exception\HttpResponseException;
/**
* 接口授权抽象类
* 接口授权抽象类.
* @class Auth
* @package plugin\account\controller\api
*/
abstract class Auth extends Controller
{
/**
* 接口类型
* 接口类型.
* @var string
*/
protected $type;
/**
* 主账号编号
* @var integer
* 主账号编号.
* @var int
*/
protected $unid;
/**
* 子账号编号
* @var integer
* 子账号编号.
* @var int
*/
protected $usid;
/**
* 终端账号接口
* @var \plugin\account\service\contract\AccountInterface
* 终端账号接口.
* @var AccountInterface
*/
protected $account;
/**
* 控制器初始化
* 控制器初始化.
*/
protected function initialize()
{
@ -69,7 +70,9 @@ abstract class Auth extends Controller
if (empty($token)) {
$token = $this->request->header('api-token', '');
}
if (empty($token)) $this->error('需要登录授权', [], 401);
if (empty($token)) {
$this->error('需要登录授权', [], 401);
}
// 读取用户账号数据
$this->account = Account::mk('', $token);
$login = $this->account->check();
@ -91,7 +94,6 @@ abstract class Auth extends Controller
/**
* 检查用户状态
* @param boolean $isBind
* @return $this
*/
protected function checkUserStatus(bool $isBind = true): Auth
@ -109,4 +111,4 @@ abstract class Auth extends Controller
}
return $this;
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller\api;
@ -28,24 +30,22 @@ use think\admin\extend\JwtExtend;
use think\exception\HttpResponseException;
/**
* 通用登录注册接口
* 通用登录注册接口.
* @class Login
* @package plugin\account\controller\api
*/
class Login extends Controller
{
/**
* 通过手机号登录
* @return void
* 通过手机号登录.
*/
public function in()
{
try {
$data = $this->_vali([
'type.require' => '类型为空',
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'verify.require' => '验证码为空'
'type.require' => '类型为空',
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'verify.require' => '验证码为空',
]);
if (Account::field($data['type']) !== 'phone') {
$this->error('不支持登录');
@ -59,7 +59,9 @@ class Login extends Controller
} else {
// 通过手机查询所有终端
$account = Account::mk('', $inset);
if ($account->isNull()) $this->error('手机未注册');
if ($account->isNull()) {
$this->error('手机未注册');
}
// 如果当前终端账号不存在则创建
if ($account->getType() !== $data['type']) {
$account = Account::mk($data['type'], $inset);
@ -79,8 +81,7 @@ class Login extends Controller
}
/**
* 自动授权登录
* @return void
* 自动授权登录.
*/
public function auto()
{
@ -89,7 +90,9 @@ class Login extends Controller
$vars = CodeExtend::decrypt($data['code'], JwtExtend::jwtkey());
if (is_array($vars) && isset($vars['unid'])) {
$user = PluginAccountUser::mk()->findOrEmpty($vars['unid']);
if ($user->isEmpty()) $this->error('无效账号!');
if ($user->isEmpty()) {
$this->error('无效账号!');
}
$inset = ['phone' => $user->getAttr('phone')];
$account = Account::mk(Account::WAP, $inset);
$account->set(['unid' => $user->getAttr('id')] + $inset);
@ -105,18 +108,17 @@ class Login extends Controller
}
/**
* 通过密码登录
* @return void
* 通过密码登录.
*/
public function pass()
{
try {
$data = $this->_vali([
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'uniqid.require' => '拼图编号为空',
'verify.require' => '拼图位置为空',
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'uniqid.require' => '拼图编号为空',
'verify.require' => '拼图位置为空',
'password.require' => '登录密码为空',
]);
if (Account::field($data['type']) !== 'phone') {
@ -128,7 +130,9 @@ class Login extends Controller
$inset = ['phone' => $data['phone'], 'deleted' => 0];
// 通过手机查询所有终端
$account = Account::mk('', $inset);
if ($account->isNull()) $this->error('手机未注册');
if ($account->isNull()) {
$this->error('手机未注册');
}
if ($account->pwdVerify($data['password'])) {
// 如果当前终端账号不存在则创建
if ($account->getType() !== $data['type']) {
@ -149,15 +153,14 @@ class Login extends Controller
/**
* 通过短信找回密码
* @return void
*/
public function forget()
{
try {
$data = $this->_vali([
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'verify.require' => '短信验证为空',
'passwd.require' => '密码不能为空',
]);
@ -165,7 +168,9 @@ class Login extends Controller
Message::clearVerifyCode($data['phone'], Message::tForget);
$inset = ['phone' => $data['phone'], 'deleted' => 0];
$account = Account::mk($data['type'], $inset);
if ($account->isNull()) $this->error('账号不存在');
if ($account->isNull()) {
$this->error('账号不存在');
}
$account->pwdModify($data['passwd']);
$this->success('重置成功', $account->expire()->get(true));
} else {
@ -179,19 +184,18 @@ class Login extends Controller
}
/**
* 用户注册绑定
* @return void
* 用户注册绑定.
*/
public function register()
{
try {
$data = $this->_vali([
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'type.require' => '接口类型为空',
'phone.mobile' => '登录手机错误',
'phone.require' => '登录手机为空',
'verify.require' => '短信验证为空',
'passwd.require' => '密码不能为空',
'fphone.default' => ''
'fphone.default' => '',
]);
if (Message::checkVerifyCode($data['verify'], $data['phone'], Message::tRegister)) {
Message::clearVerifyCode($data['phone'], Message::tRegister);
@ -214,14 +218,13 @@ class Login extends Controller
/**
* 发送短信验证码
* @return void
*/
public function send()
{
$data = $this->_vali([
'type.default' => 'login',
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'type.default' => 'login',
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'uniqid.require' => '拼图编号为空',
'verify.require' => '拼图位置为空',
]);
@ -240,7 +243,6 @@ class Login extends Controller
/**
* 生成拼图验证码
* @return void
*/
public function image()
{
@ -250,24 +252,23 @@ class Login extends Controller
];
$image = ImageVerify::render($images[array_rand($images)]);
$this->success('生成拼图成功', [
'bgimg' => $image['bgimg'],
'water' => $image['water'],
'bgimg' => $image['bgimg'],
'water' => $image['water'],
'uniqid' => $image['code'],
]);
}
/**
* 实时验证结果
* @return void
* 实时验证结果.
*/
public function verify()
{
$data = $this->_vali([
'uniqid.require' => '拼图验证为空',
'verify.require' => '拼图数值为空'
'verify.require' => '拼图数值为空',
]);
// state: [ -1:需要刷新, 0:验证失败, 1:验证成功 ]
$state = ImageVerify::verify($data['uniqid'], $data['verify']);
$this->success('验证结果', ['state' => $state]);
}
}
}

View File

@ -1,32 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller\api;
use app\wechat\service\WechatService;
use plugin\account\service\Account;
use think\admin\Controller;
use think\admin\Exception;
use think\Response;
use WeChat\Exceptions\InvalidResponseException;
use WeChat\Exceptions\LocalCacheException;
/**
* 微信服务号入口
* 微信服务号入口.
* @class Wechat
* @package plugin\account\controller\api
* @example 域名请修改为自己的地址,放到网页代码合适位置
*
* <meta name="referrer" content="always">
@ -37,9 +41,8 @@ use think\Response;
*/
class Wechat extends Controller
{
/**
* 通道认证类型
* 通道认证类型.
* @var string
*/
private const type = Account::WECHAT;
@ -51,29 +54,16 @@ class Wechat extends Controller
private $source;
/**
* 微信调度器
* 微信调度器.
* @var WechatService
*/
private $wechat;
/**
* 控制器初始化
*/
protected function initialize()
{
if (Account::field(static::type)) {
$this->wechat = WechatService::instance();
$this->source = input('source') ?: $this->request->server('http_referer', $this->request->url(true));
} else {
$this->error('接口未开通');
}
}
/**
* 生成微信网页签名
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* 生成微信网页签名.
* @throws InvalidResponseException
* @throws LocalCacheException
* @throws Exception
*/
public function jssdk()
{
@ -81,11 +71,10 @@ class Wechat extends Controller
}
/**
* 微信网页授权脚本
* @return \think\Response
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* 微信网页授权脚本.
* @throws InvalidResponseException
* @throws LocalCacheException
* @throws Exception
* @remark 基于 sessionStorage 标识的登录机制
*/
public function oauth(): Response
@ -99,9 +88,15 @@ class Wechat extends Controller
if (empty($fansinfo['is_snapshotuser'])) {
// 筛选保存数据
$data = ['appid' => WechatService::getAppid(), 'openid' => $result['openid'], 'extra' => $fansinfo];
if (isset($fansinfo['unionid'])) $data['unionid'] = $fansinfo['unionid'];
if (isset($fansinfo['nickname'])) $data['nickname'] = $fansinfo['nickname'];
if (isset($fansinfo['headimgurl'])) $data['headimg'] = $fansinfo['headimgurl'];
if (isset($fansinfo['unionid'])) {
$data['unionid'] = $fansinfo['unionid'];
}
if (isset($fansinfo['nickname'])) {
$data['nickname'] = $fansinfo['nickname'];
}
if (isset($fansinfo['headimgurl'])) {
$data['headimg'] = $fansinfo['headimgurl'];
}
$result['userinfo'] = Account::mk(static::type)->set($data, true);
// 返回数据给前端
$script[] = "window.WeChatOpenid='{$result['openid']}'";
@ -116,4 +111,17 @@ class Wechat extends Controller
$script[] = '';
return Response::create(join(";\n", $script))->contentType('application/javascript');
}
}
/**
* 控制器初始化.
*/
protected function initialize()
{
if (Account::field(static::type)) {
$this->wechat = WechatService::instance();
$this->source = input('source') ?: $this->request->server('http_referer', $this->request->url(true));
} else {
$this->error('接口未开通');
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller\api;
@ -28,39 +30,25 @@ use WeMini\Live;
use WeMini\Qrcode;
/**
* 微信小程序入口
* 微信小程序入口.
* @class Wxapp
* @package plugin\account\controller\api
*/
class Wxapp extends Controller
{
/**
* 接口通道类型
* 接口通道类型.
* @var string
*/
private $type = Account::WXAPP;
/**
* 小程序配置参数
* 小程序配置参数.
* @var array
*/
private $params;
/**
* 接口初始化
* @throws \think\admin\Exception
*/
protected function initialize()
{
if (Account::field($this->type)) {
$this->params = WechatService::getWxconf();
} else {
$this->error('接口未开通');
}
}
/**
* 换取会话
* 换取会话.
*/
public function session()
{
@ -68,9 +56,9 @@ class Wxapp extends Controller
$input = $this->_vali(['code.require' => '凭证编码为空']);
[$openid, $unionid, $sesskey] = $this->applySesskey($input['code']);
$data = [
'appid' => $this->params['appid'],
'openid' => $openid,
'unionid' => $unionid,
'appid' => $this->params['appid'],
'openid' => $openid,
'unionid' => $unionid,
'session_key' => $sesskey,
];
$this->success('授权换取成功', Account::mk($this->type)->set($data, true));
@ -83,28 +71,30 @@ class Wxapp extends Controller
}
/**
* 数据解密
* 数据解密.
*/
public function decode()
{
try {
$input = $this->_vali([
'iv.require' => '解密向量为空',
'code.require' => '授权编码为空',
'iv.require' => '解密向量为空',
'code.require' => '授权编码为空',
'encrypted.require' => '密文内容为空',
]);
[$openid, $unionid, $input['session_key']] = $this->applySesskey($input['code']);
$result = Crypt::instance($this->params)->decode($input['iv'], $input['session_key'], $input['encrypted']);
if (is_array($result) && isset($result['avatarUrl']) && isset($result['nickName'])) {
if (is_array($result) && isset($result['avatarUrl'], $result['nickName'])) {
$data = [
'extra' => $result,
'appid' => $this->params['appid'],
'openid' => $openid,
'unionid' => $unionid,
'headimg' => $result['avatarUrl'],
'extra' => $result,
'appid' => $this->params['appid'],
'openid' => $openid,
'unionid' => $unionid,
'headimg' => $result['avatarUrl'],
'nickname' => $result['nickName'],
];
if ($data['nickname'] === '微信用户') unset($data['headimg'], $data['nickname']);
if ($data['nickname'] === '微信用户') {
unset($data['headimg'], $data['nickname']);
}
$this->success('解密成功', Account::mk($this->type)->set($data, true));
} elseif (is_array($result)) {
if (!empty($result['phoneNumber'])) {
@ -127,15 +117,14 @@ class Wxapp extends Controller
}
/**
* 快速获取手机号
* @return void
* 快速获取手机号.
*/
public function phone()
{
try {
$input = $this->_vali([
'code.require' => '授权编码为空',
'openid.require' => '用户编号为空'
'code.require' => '授权编码为空',
'openid.require' => '用户编号为空',
]);
$result = Crypt::instance($this->params)->getPhoneNumber($input['code']);
if (is_array($result)) {
@ -151,36 +140,9 @@ class Wxapp extends Controller
}
}
/**
* 换取会话授权
* @param string $code 授权编号
* @return void|array [openid, unionid, sessionkey]
*/
private function applySesskey(string $code): array
{
try {
$cache = $this->app->cache->get($code, []);
if (isset($cache['openid']) && isset($cache['session_key'])) {
return [$cache['openid'], $cache['unionid'] ?? '', $cache['session_key']];
}
$result = Crypt::instance($this->params)->session($code);
if (isset($result['openid']) && isset($result['session_key'])) {
$this->app->cache->set($code, $result, 7200);
return [$result['openid'], $result['unionid'] ?? '', $result['session_key']];
} else {
$this->error($result['errmsg'] ?? '换取失败');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error("授权失败,{$exception->getMessage()}");
}
}
/**
* 获取小程序码
* @return void|\think\Response
* @return Response|void
*/
public function qrcode(): Response
{
@ -205,7 +167,7 @@ class Wxapp extends Controller
}
/**
* 获取直播列表
* 获取直播列表.
*/
public function getLiveList()
{
@ -222,15 +184,15 @@ class Wxapp extends Controller
}
/**
* 获取回放源视频
* 获取回放源视频.
*/
public function getLiveInfo()
{
try {
$data = $this->_vali([
'start.default' => 0,
'limit.default' => 10,
'action.default' => 'get_replay',
'start.default' => 0,
'limit.default' => 10,
'action.default' => 'get_replay',
'room_id.require' => '直播间号为空',
]);
$result = Live::instance($this->params)->getLiveInfo($data);
@ -242,4 +204,43 @@ class Wxapp extends Controller
$this->error($exception->getMessage());
}
}
}
/**
* 接口初始化.
* @throws \think\admin\Exception
*/
protected function initialize()
{
if (Account::field($this->type)) {
$this->params = WechatService::getWxconf();
} else {
$this->error('接口未开通');
}
}
/**
* 换取会话授权.
* @param string $code 授权编号
* @return array|void [openid, unionid, sessionkey]
*/
private function applySesskey(string $code): array
{
try {
$cache = $this->app->cache->get($code, []);
if (isset($cache['openid'], $cache['session_key'])) {
return [$cache['openid'], $cache['unionid'] ?? '', $cache['session_key']];
}
$result = Crypt::instance($this->params)->session($code);
if (isset($result['openid'], $result['session_key'])) {
$this->app->cache->set($code, $result, 7200);
return [$result['openid'], $result['unionid'] ?? '', $result['session_key']];
}
$this->error($result['errmsg'] ?? '换取失败');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error("授权失败,{$exception->getMessage()}");
}
}
}

View File

@ -1,20 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\controller\api\auth;
@ -22,20 +24,17 @@ use plugin\account\controller\api\Auth;
use plugin\account\model\PluginAccountAuth;
use plugin\account\model\PluginAccountBind;
use plugin\account\service\Message;
use think\admin\service\RuntimeService;
use think\admin\Storage;
use think\exception\HttpResponseException;
/**
* 用户账号管理
* 用户账号管理.
* @class Center
* @package plugin\account\controller\api\auth
*/
class Center extends Auth
{
/**
* 获取账号信息
* @return void
* 获取账号信息.
*/
public function get()
{
@ -43,16 +42,15 @@ class Center extends Auth
}
/**
* 修改帐号信息
* @return void
* 修改帐号信息.
*/
public function set()
{
try {
$data = $this->checkUserStatus()->_vali([
'headimg.default' => '',
'nickname.default' => '',
'password.default' => '',
'headimg.default' => '',
'nickname.default' => '',
'password.default' => '',
'region_prov.default' => '',
'region_city.default' => '',
'region_area.default' => '',
@ -66,8 +64,14 @@ class Center extends Auth
$this->account->pwdModify($data['password']);
unset($data['password']);
}
foreach ($data as $k => $v) if ($v === '') unset($data[$k]);
if (empty($data)) $this->success('无需修改', $this->account->get());
foreach ($data as $k => $v) {
if ($v === '') {
unset($data[$k]);
}
}
if (empty($data)) {
$this->success('无需修改', $this->account->get());
}
$this->success('修改成功', $this->account->bind(['id' => $this->unid], $data));
} catch (HttpResponseException $exception) {
throw $exception;
@ -77,39 +81,39 @@ class Center extends Auth
}
/**
* 注销当前账号
* @return void
* 注销当前账号.
*/
public function forbid()
{
if (($user = $this->account->user())->isExists()) try {
$this->app->db->transaction(function () use ($user) {
$user->save(['deleted' => 1, 'remark' => '用户主动申请注销账号!']);
PluginAccountAuth::mk()->where(['usid' => $this->usid])->delete();
PluginAccountBind::mk()->where(['unid' => $this->unid])->delete();
});
$this->success('账号注销成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
if (($user = $this->account->user())->isExists()) {
try {
$this->app->db->transaction(function () use ($user) {
$user->save(['deleted' => 1, 'remark' => '用户主动申请注销账号!']);
PluginAccountAuth::mk()->where(['usid' => $this->usid])->delete();
PluginAccountBind::mk()->where(['unid' => $this->unid])->delete();
});
$this->success('账号注销成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
} else {
$this->error('未完成注册!');
}
}
/**
* 绑定主账号
* @return void
* 绑定主账号.
*/
public function bind()
{
try {
$data = $this->_vali([
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'phone.mobile' => '手机号错误',
'phone.require' => '手机号为空',
'verify.require' => '验证码为空',
'passwd.default' => ''
'passwd.default' => '',
]);
if (Message::checkVerifyCode($data['verify'], $data['phone'])) {
Message::clearVerifyCode($data['phone']);
@ -137,12 +141,11 @@ class Center extends Auth
}
/**
* 解除账号关联
* @return void
* 解除账号关联.
*/
public function unbind()
{
$this->account->unBind();
$this->success('关联成功', $this->account->get());
}
}
}

View File

@ -1,101 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
$extra = [];
return array_merge($extra, [
// 通用
'用户管理' => 'User Management',
'回 收 站' => 'Recycle Bin',
'排序权重' => 'Sort Weight',
'头像' => 'Avatar',
'账号状态' => 'Account Status',
'操作面板' => 'Actions',
'已激活' => 'Activated',
'已禁用' => 'Disabled',
'已启用' => 'Enabled',
'已冻结的用户' => 'Frozen Users',
'已激活的用户' => 'Activated Users',
'删 除' => 'Delete',
'保存数据' => 'Save Data',
'取消编辑' => 'Cancel Edit',
'保存配置' => 'Save Configuration',
'取消修改' => 'Cancel Modification',
'确定要取消编辑吗?' => 'Are you sure you want to cancel editing?',
'确定要取消修改吗?' => 'Are you sure you want to cancel the modification?',
'用户管理' => 'User Management',
'回 收 站' => 'Recycle Bin',
'排序权重' => 'Sort Weight',
'头像' => 'Avatar',
'账号状态' => 'Account Status',
'操作面板' => 'Actions',
'已激活' => 'Activated',
'已禁用' => 'Disabled',
'已启用' => 'Enabled',
'已冻结的用户' => 'Frozen Users',
'已激活的用户' => 'Activated Users',
'删 除' => 'Delete',
'保存数据' => 'Save Data',
'取消编辑' => 'Cancel Edit',
'保存配置' => 'Save Configuration',
'取消修改' => 'Cancel Modification',
'确定要取消编辑吗?' => 'Are you sure you want to cancel editing?',
'确定要取消修改吗?' => 'Are you sure you want to cancel the modification?',
'确定要永久删除此账号吗?' => 'Are you sure you want to permanently delete this account?',
'全部' => 'All',
'搜 索' => 'Search',
'导 出' => 'Export',
'全部' => 'All',
'搜 索' => 'Search',
'导 出' => 'Export',
// 设备管理
'账号接口配置' => 'Account Interface Configuration',
'账号配置' => 'Account Configuration',
'终端类型' => 'Device Type',
'绑定手机' => 'Bound Mobile',
'用户姓名' => 'User Name',
'用户昵称' => 'User Nickname',
'关联账号' => 'Associated Account',
'使用状态' => 'Status',
'首次登录' => 'First Login',
'请输入绑定手机' => 'Please enter bound mobile',
'请输入用户姓名' => 'Please enter user name',
'请输入用户昵称' => 'Please enter user nickname',
'请选择绑定时间' => 'Please select binding time',
'用户账号数据' => 'User Account Data',
'账号接口配置' => 'Account Interface Configuration',
'账号配置' => 'Account Configuration',
'终端类型' => 'Device Type',
'绑定手机' => 'Bound Mobile',
'用户姓名' => 'User Name',
'用户昵称' => 'User Nickname',
'关联账号' => 'Associated Account',
'使用状态' => 'Status',
'首次登录' => 'First Login',
'请输入绑定手机' => 'Please enter bound mobile',
'请输入用户姓名' => 'Please enter user name',
'请输入用户昵称' => 'Please enter user nickname',
'请选择绑定时间' => 'Please select binding time',
'用户账号数据' => 'User Account Data',
// 主账号管理
'用户编号' => 'User Code',
'绑定邮箱' => 'Bound Email',
'绑定时间' => 'Binding Time',
'请输入用户编号' => 'Please enter user code',
'请输入绑定邮箱' => 'Please enter bound email',
'用户编号' => 'User Code',
'绑定邮箱' => 'Bound Email',
'绑定时间' => 'Binding Time',
'请输入用户编号' => 'Please enter user code',
'请输入绑定邮箱' => 'Please enter bound email',
// 消息管理
'短信配置' => 'SMS Configuration',
'消息编号' => 'Message Code',
'短信类型' => 'SMS Type',
'发送手机' => 'Send Mobile',
'短信内容' => 'SMS Content',
'发送时间' => 'Send Time',
'发送失败' => 'Send Failed',
'发送成功' => 'Send Success',
'请输入消息编号' => 'Please enter message code',
'请输入发送手机' => 'Please enter send mobile',
'请输入短信内容' => 'Please enter SMS content',
'请选择发送时间' => 'Please select send time',
'短信配置' => 'SMS Configuration',
'消息编号' => 'Message Code',
'短信类型' => 'SMS Type',
'发送手机' => 'Send Mobile',
'短信内容' => 'SMS Content',
'发送时间' => 'Send Time',
'发送失败' => 'Send Failed',
'发送成功' => 'Send Success',
'请输入消息编号' => 'Please enter message code',
'请输入发送手机' => 'Please enter send mobile',
'请输入短信内容' => 'Please enter SMS content',
'请选择发送时间' => 'Please select send time',
// 短信配置
'服务区域' => 'Service Region',
'阿里云账号' => 'Aliyun Account',
'阿里云密钥' => 'Aliyun Secret Key',
'短信签名' => 'SMS Signature',
'短信模板编号' => 'SMS Template Code',
'请输入阿里云账号' => 'Please enter Aliyun account',
'请输入阿里云密钥' => 'Please enter Aliyun secret key',
'请输入短信签名' => 'Please enter SMS signature',
'请输入短信模板编号' => 'Please enter SMS template code',
'服务区域' => 'Service Region',
'阿里云账号' => 'Aliyun Account',
'阿里云密钥' => 'Aliyun Secret Key',
'短信签名' => 'SMS Signature',
'短信模板编号' => 'SMS Template Code',
'请输入阿里云账号' => 'Please enter Aliyun account',
'请输入阿里云密钥' => 'Please enter Aliyun secret key',
'请输入短信签名' => 'Please enter SMS signature',
'请输入短信模板编号' => 'Please enter SMS template code',
// 账号配置
'认证有效时间' => 'Authentication Expire Time',
'登录自动注册' => 'Auto Register on Login',
'默认昵称前缀' => 'Default Nickname Prefix',
'默认用户头像' => 'Default User Avatar',
'开放接口通道' => 'Open Interface Channels',
'认证有效时间' => 'Authentication Expire Time',
'登录自动注册' => 'Auto Register on Login',
'默认昵称前缀' => 'Default Nickname Prefix',
'默认用户头像' => 'Default User Avatar',
'开放接口通道' => 'Open Interface Channels',
'设置为 0 表示永不过期,建议设置有效时间达到系统自动回收令牌。' => 'Set to 0 means never expires. It is recommended to set an expiration time for automatic token recycling.',
'启用自动登录时,通过验证码登录时账号不存在会自动创建!' => 'When auto login is enabled, accounts that do not exist will be automatically created when logging in with verification code!',
'用户绑定账号后会自动使用此前缀与手机号后4位拼接为新默认昵称。' => 'After user binds account, this prefix will be automatically combined with the last 4 digits of mobile number as new default nickname.',
'当用户未设置头像时,自动使用此头像设置的图片链接。' => 'When user has not set avatar, automatically use the image link set in this avatar.',
'请输入默认昵称前缀' => 'Please enter default nickname prefix',
'请输入默认昵称前缀' => 'Please enter default nickname prefix',
]);

View File

@ -1,37 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | Account Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/think-plugs-account
// | github 代码仓库https://github.com/zoujingli/think-plugs-account
// +----------------------------------------------------------------------
declare (strict_types=1);
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | Payment Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\account\model;
use think\admin\Model;
/**
* 模型抽象类
* 模型抽象类.
* @class Abs
* @package plugin\account\model
*/
abstract class Abs extends Model
{
/**
* 格式化输出时间
* 格式化输出时间.
* @param mixed $value
* @return string
*/
public function getCreateTimeAttr($value): string
{
@ -39,9 +38,8 @@ abstract class Abs extends Model
}
/**
* 格式化输出时间
* 格式化输出时间.
* @param mixed $value
* @return string
*/
public function getUpdateTimeAttr($value): string
{
@ -49,9 +47,8 @@ abstract class Abs extends Model
}
/**
* 时间写入格式化
* 时间写入格式化.
* @param mixed $value
* @return string
*/
public function setCreateTimeAttr($value): string
{
@ -59,9 +56,8 @@ abstract class Abs extends Model
}
/**
* 时间写入格式化
* 时间写入格式化.
* @param mixed $value
* @return string
*/
public function setUpdateTimeAttr($value): string
{
@ -69,9 +65,8 @@ abstract class Abs extends Model
}
/**
* 字段属性处理
* 字段属性处理.
* @param mixed $value
* @return string
*/
public function setExtraAttr($value): string
{
@ -79,12 +74,11 @@ abstract class Abs extends Model
}
/**
* 字段属性处理
* 字段属性处理.
* @param mixed $value
* @return array
*/
public function getExtraAttr($value): array
{
return empty($value) ? [] : (is_string($value) ? json_decode($value, true) : $value);
}
}
}

Some files were not shown because too many files have changed in this diff Show More