文件还在测试中

This commit is contained in:
2026-08-08 15:53:53 +08:00
parent 5f1e7adb64
commit 8101177cb5
241 changed files with 18074 additions and 22 deletions
+166
View File
@@ -0,0 +1,166 @@
<?php
namespace App\Controllers\Admin;
use App\Controllers\Controller;
use Core\App;
use Core\Db;
use Core\Installer;
/**
* 后台:数据库升级
* - 将升级包(*.sql)放入 install/upgrades/ 目录后,本页自动提示「可升级」。
* - 支持单个升级与一键全部升级;每次执行写入 db_upgrades 记录(文件名 / 哈希 / 时间 / 操作人)。
* - 内容发生变更的已升级包会被重新标记为「需更新」。
* 路由:/admin/upgrade -> 升级面板
* /admin/upgrade/apply/<file.sql> -> 升级单个
* /admin/upgrade/applyall -> 一键全部升级
* /admin/upgrade/init -> 基础数据/表结构初始化(POST,仅超管)
*/
class UpgradeController extends Controller
{
protected $layout = 'layouts/admin';
private function dir(): string
{
return BASE_PATH . '/install/upgrades';
}
public function index()
{
admin_required();
if (Db::driver() !== 'mysql') {
return $this->view('admin/upgrade', ['driver' => 'file']);
}
$this->requireSuper();
Installer::ensureUpgradeLog();
$files = $this->scan();
$applied = $this->appliedMap();
$list = [];
foreach ($files as $f) {
$name = basename($f);
$hash = md5_file($f);
$state = !isset($applied[$name]) ? 'pending'
: ($applied[$name] !== $hash ? 'changed' : 'done');
$list[] = [
'name' => $name,
'size' => filesize($f),
'mtime' => filemtime($f),
'state' => $state,
];
}
// 排序:待升级 / 已变更 在前,已应用在后
$rank = ['pending' => 0, 'changed' => 1, 'done' => 2];
usort($list, fn($a, $b) => ($rank[$a['state']] ?? 9) - ($rank[$b['state']] ?? 9));
$pending = count(array_filter($list, fn($x) => $x['state'] !== 'done'));
$history = Db::query("SELECT * FROM db_upgrades ORDER BY applied_at DESC, id DESC LIMIT 50")->fetchAll();
return $this->view('admin/upgrade', [
'driver' => 'mysql',
'list' => $list,
'pending' => $pending,
'history' => $history,
]);
}
/** 升级单个升级包 */
public function apply($file = null)
{
admin_required();
$this->requireSuper();
$file = basename((string)$file);
$path = $this->dir() . '/' . $file;
if (!is_file($path) || !preg_match('/\.sql$/i', $file)) {
$this->flash('升级包不存在', 'err');
$this->redirect('admin/upgrade');
return '';
}
try {
Installer::applySqlFile($path);
Installer::ensureUpgradeLog();
Db::query(
"INSERT INTO db_upgrades (file, hash, applied_at, applied_by, note) VALUES (?, ?, ?, ?, ?)",
[$file, md5_file($path), date('Y-m-d H:i:s'), ($_SESSION['admin']['username'] ?? 'admin'), '']
);
$this->flash("已升级:{$file}", 'ok');
} catch (\Throwable $e) {
$this->flash('升级失败:' . $e->getMessage(), 'err');
}
$this->redirect('admin/upgrade');
return '';
}
/** 一键升级全部待处理 */
public function applyAll()
{
admin_required();
$this->requireSuper();
$files = $this->scan();
$applied = $this->appliedMap();
$done = 0;
foreach ($files as $f) {
$name = basename($f);
$hash = md5_file($f);
if (isset($applied[$name]) && $applied[$name] === $hash) continue;
try {
Installer::applySqlFile($f);
Installer::ensureUpgradeLog();
Db::query(
"INSERT INTO db_upgrades (file, hash, applied_at, applied_by, note) VALUES (?, ?, ?, ?, ?)",
[$name, $hash, date('Y-m-d H:i:s'), ($_SESSION['admin']['username'] ?? 'admin'), '']
);
$done++;
} catch (\Throwable $e) {
$this->flash('升级失败:' . e($e->getMessage()), 'err');
$this->redirect('admin/upgrade');
return '';
}
}
$this->flash($done > 0 ? "已批量升级 {$done} 个升级包" : '没有需要升级的包', $done > 0 ? 'ok' : 'err');
$this->redirect('admin/upgrade');
return '';
}
/** 基础数据/表结构初始化(保留旧版能力:补齐新模块表与种子) */
public function init()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $this->redirect('admin/upgrade'); return ''; }
admin_required();
$this->requireSuper();
if (!csrf_check()) {
$this->flash('表单已过期,请刷新后重试', 'err');
$this->redirect('admin/upgrade');
return '';
}
$msgs = Installer::upgrade();
$this->flash('基础数据升级完成 ✓ ' . implode('', $msgs), 'ok');
$this->redirect('admin/upgrade');
return '';
}
/* ---------------- 工具 ---------------- */
private function requireSuper(): void
{
if (!is_admin() || admin_role() !== 'super_admin') {
App::forbidden('仅超级管理员可执行数据库升级');
}
}
private function scan(): array
{
$d = $this->dir();
return is_dir($d) ? (glob($d . '/*.sql') ?: []) : [];
}
private function appliedMap(): array
{
try {
return Db::query("SELECT file, hash FROM db_upgrades")->fetchAll(\PDO::FETCH_KEY_PAIR);
} catch (\Throwable $e) {
return [];
}
}
}