mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-09-04 23:13:26 +08:00
refactor(agents): 删除 tools:agent:publish 命令,补全 helper.php 函数覆盖机制,修正多处文档 bug
- 删除 tools:agent:publish 整套(不再兼容多套 IDE,只保留 .agents 目录) - helper.php 全部 27 个全局函数加 if (!function_exists()) 包裹,项目侧可在 app/common.php 定义同名函数覆盖 - ulthon-file-override-mechanism.md 新增全局函数覆盖章节 - AGENTS.md 删除智能体指导章节,PHP 8+ 改为 8.0+,MySQL 8+ 改为 5.7+ - AGENTS.md 项目结构树补全 tests/、extend/think/、source/ 子项 - README.md PHP 版本统一为 8.0+ - ulthon-base-app-architecture SKILL 路径补 admin/service/ 段 - ulthon-tools-http-call SKILL 补 --page-data 参数 - ulthon-naming-convention 补元数据头 - ulthon-update-workflow 统一 extend/think/ 归类
This commit is contained in:
@@ -1,277 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\agent;
|
||||
|
||||
use app\common\console\Command;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\App;
|
||||
|
||||
class ToolsAgentPublishBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setName('tools:agent:publish')
|
||||
->setDescription('发布 AGENTS.md 与 .agent 到兼容目标(复制 rules/skills;可选生成 CLAUDE.md)')
|
||||
->addOption('target', 't', Option::VALUE_OPTIONAL, '发布目标:trae|opencode|roocode|cursor|claude|all', 'all')
|
||||
->addOption('dry-run', null, Option::VALUE_NONE, '只输出将要写入/覆盖的清单,不落盘')
|
||||
->addOption('clean', null, Option::VALUE_NONE, '清理目标中由发布器生成的内容(仅影响 rules/skills 与发布文件)')
|
||||
->addOption('force', 'f', Option::VALUE_NONE, '跳过覆盖确认');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$rootPath = rtrim(App::getRootPath(), "\\/ \t\n\r\0\x0B");
|
||||
|
||||
$sourceAgentsPath = $rootPath . DIRECTORY_SEPARATOR . 'AGENTS.md';
|
||||
$sourceRulesDir = $rootPath . DIRECTORY_SEPARATOR . '.agent' . DIRECTORY_SEPARATOR . 'rules';
|
||||
$sourceSkillsDir = $rootPath . DIRECTORY_SEPARATOR . '.agent' . DIRECTORY_SEPARATOR . 'skills';
|
||||
|
||||
if (!is_file($sourceAgentsPath)) {
|
||||
$output->error('缺少单一事实来源文件:' . $sourceAgentsPath);
|
||||
return;
|
||||
}
|
||||
if (!is_dir($sourceRulesDir)) {
|
||||
$output->error('缺少单一事实来源目录:' . $sourceRulesDir);
|
||||
return;
|
||||
}
|
||||
if (!is_dir($sourceSkillsDir)) {
|
||||
$output->error('缺少单一事实来源目录:' . $sourceSkillsDir);
|
||||
return;
|
||||
}
|
||||
|
||||
$target = strtolower((string)$input->getOption('target'));
|
||||
if ($target === '') {
|
||||
$target = 'all';
|
||||
}
|
||||
|
||||
$supportedTargets = ['trae', 'opencode', 'roocode', 'cursor', 'claude', 'all'];
|
||||
if (!in_array($target, $supportedTargets, true)) {
|
||||
$output->error('不支持的 target:' . $target . '(可选:' . implode('|', $supportedTargets) . ')');
|
||||
return;
|
||||
}
|
||||
|
||||
$dryRun = (bool)$input->getOption('dry-run');
|
||||
$clean = (bool)$input->getOption('clean');
|
||||
|
||||
$targets = $target === 'all' ? ['trae', 'opencode', 'roocode', 'cursor', 'claude'] : [$target];
|
||||
|
||||
$writeActions = [];
|
||||
$deleteActions = [];
|
||||
|
||||
$agentsContent = file_get_contents($sourceAgentsPath);
|
||||
if ($agentsContent === false) {
|
||||
$output->error('读取失败:' . $sourceAgentsPath);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($targets as $t) {
|
||||
if (in_array($t, ['trae', 'opencode', 'roocode', 'cursor'], true)) {
|
||||
$distRoot = $rootPath . DIRECTORY_SEPARATOR . '.' . $t;
|
||||
$distRules = $distRoot . DIRECTORY_SEPARATOR . 'rules';
|
||||
$distSkills = $distRoot . DIRECTORY_SEPARATOR . 'skills';
|
||||
|
||||
if ($t === 'cursor') {
|
||||
$deleteActions[] = $distRules . DIRECTORY_SEPARATOR . 'ulthon-framework.mdc';
|
||||
}
|
||||
|
||||
if ($clean) {
|
||||
$deleteActions[] = $distRules;
|
||||
$deleteActions[] = $distSkills;
|
||||
}
|
||||
|
||||
$writeActions = array_merge($writeActions, $this->planCopyDir($sourceRulesDir, $distRules));
|
||||
$writeActions = array_merge($writeActions, $this->planCopyDir($sourceSkillsDir, $distSkills));
|
||||
}
|
||||
|
||||
if ($t === 'claude') {
|
||||
$distClaude = $rootPath . DIRECTORY_SEPARATOR . 'CLAUDE.md';
|
||||
if ($clean) {
|
||||
$deleteActions[] = $distClaude;
|
||||
}
|
||||
$writeActions = array_merge($writeActions, $this->planWriteFile($distClaude, $agentsContent));
|
||||
}
|
||||
}
|
||||
|
||||
$deleteActions = array_values(array_unique(array_filter($deleteActions, 'strlen')));
|
||||
|
||||
$plannedDeletes = $this->filterExistingDeletes($deleteActions);
|
||||
$plannedWrites = $this->filterEffectiveWrites($writeActions, $clean);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>=== tools:agent:publish 计划 ===</info>');
|
||||
$output->writeln('target:' . $target);
|
||||
$output->writeln('dry-run:' . ($dryRun ? 'yes' : 'no'));
|
||||
$output->writeln('clean:' . ($clean ? 'yes' : 'no'));
|
||||
$output->writeln('');
|
||||
|
||||
if (empty($plannedDeletes) && empty($plannedWrites)) {
|
||||
$output->writeln('<comment>无变更:目标已是最新状态。</comment>');
|
||||
$output->writeln('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($plannedDeletes)) {
|
||||
$output->writeln('<comment>将删除:</comment>');
|
||||
foreach ($plannedDeletes as $path) {
|
||||
$output->writeln(' - ' . $path);
|
||||
}
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
if (!empty($plannedWrites)) {
|
||||
$output->writeln('<comment>将写入:</comment>');
|
||||
foreach ($plannedWrites as $item) {
|
||||
$output->writeln(' - [' . $item['mode'] . '] ' . $item['dist']);
|
||||
}
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
if ($dryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$output->confirm($input, '将执行上述写入/覆盖/删除操作,是否继续?', true)) {
|
||||
$output->comment('已取消。');
|
||||
$output->newLine();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($plannedDeletes as $path) {
|
||||
$this->deletePath($path);
|
||||
}
|
||||
|
||||
foreach ($plannedWrites as $item) {
|
||||
$this->ensureDir(dirname($item['dist']));
|
||||
file_put_contents($item['dist'], $item['content']);
|
||||
}
|
||||
|
||||
$output->info('发布完成。');
|
||||
$output->newLine();
|
||||
}
|
||||
|
||||
protected function planCopyDir(string $sourceDir, string $distDir): array
|
||||
{
|
||||
$actions = [];
|
||||
if (!is_dir($sourceDir)) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
|
||||
$sourceDirNormalized = rtrim($sourceDir, "\\/") . DIRECTORY_SEPARATOR;
|
||||
foreach ($iterator as $fileInfo) {
|
||||
if (!$fileInfo->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$src = $fileInfo->getPathname();
|
||||
$relative = substr($src, strlen($sourceDirNormalized));
|
||||
$dist = $distDir . DIRECTORY_SEPARATOR . str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $relative);
|
||||
|
||||
$content = file_get_contents($src);
|
||||
if ($content === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$actions[] = [
|
||||
'dist' => $dist,
|
||||
'content' => $content,
|
||||
];
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
protected function planWriteFile(string $dist, string $content): array
|
||||
{
|
||||
return [[
|
||||
'dist' => $dist,
|
||||
'content' => $content,
|
||||
]];
|
||||
}
|
||||
|
||||
protected function filterEffectiveWrites(array $actions, bool $forceWrite = false): array
|
||||
{
|
||||
$result = [];
|
||||
$resultMap = [];
|
||||
foreach ($actions as $item) {
|
||||
$dist = (string)($item['dist'] ?? '');
|
||||
$content = (string)($item['content'] ?? '');
|
||||
if ($dist === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mode = 'create';
|
||||
if (is_file($dist)) {
|
||||
$existing = file_get_contents($dist);
|
||||
if (!$forceWrite && $existing !== false && $existing === $content) {
|
||||
continue;
|
||||
}
|
||||
$mode = 'update';
|
||||
}
|
||||
|
||||
$resultMap[$dist] = [
|
||||
'dist' => $dist,
|
||||
'content' => $content,
|
||||
'mode' => $mode,
|
||||
];
|
||||
}
|
||||
$result = array_values($resultMap);
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function filterExistingDeletes(array $deleteActions): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($deleteActions as $path) {
|
||||
if (is_file($path) || is_dir($path)) {
|
||||
$result[] = $path;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function deletePath(string $path): void
|
||||
{
|
||||
if (is_file($path)) {
|
||||
@unlink($path);
|
||||
return;
|
||||
}
|
||||
if (!is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($iterator as $fileInfo) {
|
||||
if ($fileInfo->isDir()) {
|
||||
@rmdir($fileInfo->getPathname());
|
||||
continue;
|
||||
}
|
||||
@unlink($fileInfo->getPathname());
|
||||
}
|
||||
|
||||
@rmdir($path);
|
||||
}
|
||||
|
||||
protected function ensureDir(string $dir): void
|
||||
{
|
||||
if ($dir === '' || is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
@mkdir($dir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,41 +225,45 @@ if (!function_exists('get_session_admin')) {
|
||||
}
|
||||
}
|
||||
|
||||
function read_header_token()
|
||||
{
|
||||
$header_authorization = Request::header('Authorization');
|
||||
if (!empty($header_authorization)) {
|
||||
$token = explode(' ', $header_authorization)[1];
|
||||
if (!function_exists('read_header_token')) {
|
||||
function read_header_token()
|
||||
{
|
||||
$header_authorization = Request::header('Authorization');
|
||||
if (!empty($header_authorization)) {
|
||||
$token = explode(' ', $header_authorization)[1];
|
||||
|
||||
return $token;
|
||||
return $token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function json_message($data = [], $code = 0, $msg = '')
|
||||
{
|
||||
if (is_string($data)) {
|
||||
if (strpos($data, 'http') === 0 || strpos($data, '/') === 0) {
|
||||
if (!function_exists('json_message')) {
|
||||
function json_message($data = [], $code = 0, $msg = '')
|
||||
{
|
||||
if (is_string($data)) {
|
||||
if (strpos($data, 'http') === 0 || strpos($data, '/') === 0) {
|
||||
$data = [
|
||||
'jump_to_url' => $data,
|
||||
];
|
||||
} else {
|
||||
$code = $code;
|
||||
$msg = $data;
|
||||
$data = [];
|
||||
}
|
||||
} elseif ($data instanceof Url) {
|
||||
$data = [
|
||||
'jump_to_url' => $data,
|
||||
'jump_to_url' => (string) $data,
|
||||
];
|
||||
} else {
|
||||
$code = $code;
|
||||
$msg = $data;
|
||||
$data = [];
|
||||
}
|
||||
} elseif ($data instanceof Url) {
|
||||
$data = [
|
||||
'jump_to_url' => (string) $data,
|
||||
];
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data,
|
||||
]);
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('unparse_url')) {
|
||||
@@ -279,200 +283,229 @@ if (!function_exists('unparse_url')) {
|
||||
}
|
||||
}
|
||||
|
||||
function build_upload_url($url, $upload_type = null)
|
||||
{
|
||||
if (is_null($upload_type)) {
|
||||
$upload_type = sysconfig('upload', 'upload_type', 'local_public');
|
||||
}
|
||||
if (!function_exists('build_upload_url')) {
|
||||
function build_upload_url($url, $upload_type = null)
|
||||
{
|
||||
if (is_null($upload_type)) {
|
||||
$upload_type = sysconfig('upload', 'upload_type', 'local_public');
|
||||
}
|
||||
|
||||
return Filesystem::disk($upload_type)->url($url);
|
||||
return Filesystem::disk($upload_type)->url($url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行扩展事件.
|
||||
*
|
||||
* @param string $name 事件名称
|
||||
* @param string $key 处理的key
|
||||
* @param string $type 处理模式
|
||||
* @param array $params 传参
|
||||
* @return array
|
||||
*/
|
||||
function event_handle_result($name, $key, $type = 'all', $params = []) : array
|
||||
{
|
||||
$list_result = Event::trigger($name, $params);
|
||||
if (!function_exists('event_handle_result')) {
|
||||
/**
|
||||
* 执行扩展事件.
|
||||
*
|
||||
* @param string $name 事件名称
|
||||
* @param string $key 处理的key
|
||||
* @param string $type 处理模式
|
||||
* @param array $params 传参
|
||||
* @return array
|
||||
*/
|
||||
function event_handle_result($name, $key, $type = 'all', $params = []) : array
|
||||
{
|
||||
$list_result = Event::trigger($name, $params);
|
||||
|
||||
$result = [];
|
||||
$result = [];
|
||||
|
||||
foreach ($list_result as $key_event => $value_event) {
|
||||
if (!isset($value_event[$key])) {
|
||||
if (Env::get('adminsystem.strict_event')) {
|
||||
throw new EventException("Event view {$name} trigger a result without a {$key}");
|
||||
foreach ($list_result as $key_event => $value_event) {
|
||||
if (!isset($value_event[$key])) {
|
||||
if (Env::get('adminsystem.strict_event')) {
|
||||
throw new EventException("Event view {$name} trigger a result without a {$key}");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($type == 'all') {
|
||||
$result[] = $value_event[$key];
|
||||
} elseif ($type == 'last') {
|
||||
$result = [];
|
||||
$result[] = $value_event[$key];
|
||||
} elseif ($type == 'first') {
|
||||
$result[] = $value_event[$key];
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($type == 'all') {
|
||||
$result[] = $value_event[$key];
|
||||
} elseif ($type == 'last') {
|
||||
$result = [];
|
||||
$result[] = $value_event[$key];
|
||||
} elseif ($type == 'first') {
|
||||
$result[] = $value_event[$key];
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符拼接通用处理函数.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return void
|
||||
*/
|
||||
function event_handle_string($name, $type)
|
||||
{
|
||||
$list_result = event_handle_result($name, $type);
|
||||
$content = implode('', $list_result);
|
||||
if (!function_exists('event_handle_string')) {
|
||||
/**
|
||||
* 字符拼接通用处理函数.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return void
|
||||
*/
|
||||
function event_handle_string($name, $type)
|
||||
{
|
||||
$list_result = event_handle_result($name, $type);
|
||||
$content = implode('', $list_result);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
function event_view_content($name)
|
||||
{
|
||||
return event_handle_string($name, 'view_content');
|
||||
}
|
||||
|
||||
function event_view_replace($content, $name)
|
||||
{
|
||||
$list_result = event_handle_result($name, 'view_replace');
|
||||
|
||||
$content_event = implode('', $list_result);
|
||||
|
||||
if (empty($content_event)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $content_event;
|
||||
}
|
||||
|
||||
function event_view_replace_js($name)
|
||||
{
|
||||
$list_result = event_handle_result($name, 'view_replace_js');
|
||||
|
||||
$content_event = implode('', $list_result);
|
||||
|
||||
return "<script id='event-replace-js-{$name}' type='text/plain'>{$content_event}</script>";
|
||||
}
|
||||
|
||||
function event_response($name, $params = [])
|
||||
{
|
||||
$list_result = event_handle_result($name, 'response', 'last', $params);
|
||||
|
||||
if (empty($list_result)) {
|
||||
return;
|
||||
if (!function_exists('event_view_content')) {
|
||||
function event_view_content($name)
|
||||
{
|
||||
return event_handle_string($name, 'view_content');
|
||||
}
|
||||
|
||||
$response = $list_result[0];
|
||||
|
||||
if (is_string($response)) {
|
||||
$response = View::create($response);
|
||||
}
|
||||
|
||||
throw new HttpResponseException($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以扩展的架构定位app下的文件位置.
|
||||
*
|
||||
* @param string $file_path 文件路径,不要以/开头,不需要以app开头,会自动定位 app 或 extend/base。
|
||||
* @return string
|
||||
*/
|
||||
function app_file_path($file_path)
|
||||
{
|
||||
$app_file_path = App::getRootPath() . 'app' . DIRECTORY_SEPARATOR . $file_path;
|
||||
if (!is_file($app_file_path)) {
|
||||
$app_file_path = App::getRootPath() . 'extend' . DIRECTORY_SEPARATOR . 'base' . DIRECTORY_SEPARATOR . $file_path;
|
||||
}
|
||||
if (!function_exists('event_view_replace')) {
|
||||
function event_view_replace($content, $name)
|
||||
{
|
||||
$list_result = event_handle_result($name, 'view_replace');
|
||||
|
||||
return $app_file_path;
|
||||
}
|
||||
$content_event = implode('', $list_result);
|
||||
|
||||
function array_to_table($array_tree, $prefix_key = '')
|
||||
{
|
||||
$table = [];
|
||||
|
||||
foreach ($array_tree as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$table = array_merge($table, array_to_table($value, $key . '.'));
|
||||
} else {
|
||||
$table[] = [
|
||||
'key' => $prefix_key . $key,
|
||||
'value' => $value,
|
||||
];
|
||||
if (empty($content_event)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $content_event;
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
function format_bytes($size, $delimiter = '')
|
||||
{
|
||||
if (is_null($size)) {
|
||||
return '0B';
|
||||
if (!function_exists('event_view_replace_js')) {
|
||||
function event_view_replace_js($name)
|
||||
{
|
||||
$list_result = event_handle_result($name, 'view_replace_js');
|
||||
|
||||
$content_event = implode('', $list_result);
|
||||
|
||||
return "<script id='event-replace-js-{$name}' type='text/plain'>{$content_event}</script>";
|
||||
}
|
||||
$units = ['B', 'K', 'M', 'G', 'T', 'P'];
|
||||
for ($i = 0; $size >= 1024 && $i < 5; $i++) {
|
||||
$size /= 1024;
|
||||
}
|
||||
|
||||
if (!function_exists('event_response')) {
|
||||
function event_response($name, $params = [])
|
||||
{
|
||||
$list_result = event_handle_result($name, 'response', 'last', $params);
|
||||
|
||||
if (empty($list_result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $list_result[0];
|
||||
|
||||
if (is_string($response)) {
|
||||
$response = View::create($response);
|
||||
}
|
||||
|
||||
throw new HttpResponseException($response);
|
||||
}
|
||||
|
||||
return round($size, 2) . $delimiter . $units[$i];
|
||||
}
|
||||
function parse_bytes($size)
|
||||
{
|
||||
$unit = strtolower(substr($size, -1));
|
||||
$size = (int) $size;
|
||||
switch ($unit) {
|
||||
case 'b':
|
||||
break;
|
||||
case 'k':
|
||||
$size *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
$size *= 1024 * 1024;
|
||||
break;
|
||||
case 'g':
|
||||
$size *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 't':
|
||||
$size *= 1024 * 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 'p':
|
||||
$size *= 1024 * 1024 * 1024 * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
return $size;
|
||||
|
||||
if (!function_exists('app_file_path')) {
|
||||
/**
|
||||
* 以扩展的架构定位app下的文件位置.
|
||||
*
|
||||
* @param string $file_path 文件路径,不要以/开头,不需要以app开头,会自动定位 app 或 extend/base。
|
||||
* @return string
|
||||
*/
|
||||
function app_file_path($file_path)
|
||||
{
|
||||
$app_file_path = App::getRootPath() . 'app' . DIRECTORY_SEPARATOR . $file_path;
|
||||
if (!is_file($app_file_path)) {
|
||||
$app_file_path = App::getRootPath() . 'extend' . DIRECTORY_SEPARATOR . 'base' . DIRECTORY_SEPARATOR . $file_path;
|
||||
}
|
||||
|
||||
return $app_file_path;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
function get_store_value($key, $default = null)
|
||||
{
|
||||
return StoreValueTools::get($key, $default);
|
||||
if (!function_exists('array_to_table')) {
|
||||
function array_to_table($array_tree, $prefix_key = '')
|
||||
{
|
||||
$table = [];
|
||||
|
||||
foreach ($array_tree as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$table = array_merge($table, array_to_table($value, $key . '.'));
|
||||
} else {
|
||||
$table[] = [
|
||||
'key' => $prefix_key . $key,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
|
||||
function set_store_value($key, $value)
|
||||
{
|
||||
return StoreValueTools::set($key, $value);
|
||||
if (!function_exists('format_bytes')) {
|
||||
function format_bytes($size, $delimiter = '')
|
||||
{
|
||||
if (is_null($size)) {
|
||||
return '0B';
|
||||
}
|
||||
$units = ['B', 'K', 'M', 'G', 'T', 'P'];
|
||||
for ($i = 0; $size >= 1024 && $i < 5; $i++) {
|
||||
$size /= 1024;
|
||||
}
|
||||
|
||||
return round($size, 2) . $delimiter . $units[$i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_bytes')) {
|
||||
function parse_bytes($size)
|
||||
{
|
||||
$unit = strtolower(substr($size, -1));
|
||||
$size = (int) $size;
|
||||
switch ($unit) {
|
||||
case 'b':
|
||||
break;
|
||||
case 'k':
|
||||
$size *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
$size *= 1024 * 1024;
|
||||
break;
|
||||
case 'g':
|
||||
$size *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 't':
|
||||
$size *= 1024 * 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 'p':
|
||||
$size *= 1024 * 1024 * 1024 * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
return $size;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_store_value')) {
|
||||
function get_store_value($key, $default = null)
|
||||
{
|
||||
return StoreValueTools::get($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_store_value')) {
|
||||
function set_store_value($key, $value)
|
||||
{
|
||||
return StoreValueTools::set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_site_version_key')) {
|
||||
function get_site_version_key()
|
||||
{
|
||||
return sysconfig('site', 'site_version') . '-' . Version::VERSION . '-' . Version::PRODUCT_VERSION . '-' . Version::LAYUI_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('format_null_value')) {
|
||||
function format_null_value($value)
|
||||
{
|
||||
@@ -483,6 +516,7 @@ if (!function_exists('format_null_value')) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('ctype_numeric')) {
|
||||
function ctype_numeric($input)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user