__DIR__ . '/sql/upgrades/v1.7.sql', '1.8' => __DIR__ . '/sql/upgrades/v1.8.sql', '2.0' => __DIR__ . '/sql/upgrades/v2.0.sql', '2.0.1' => __DIR__ . '/sql/upgrades/v2.0.1.sql', '2.1' => __DIR__ . '/sql/upgrades/v2.1.sql', '2.2' => __DIR__ . '/sql/upgrades/v2.2.sql', ]; /** * 读取 backend/.env 文件并解析数据库配置 */ function readEnvConfig($envPath) { if (!file_exists($envPath)) { throw new RuntimeException('配置文件不存在: ' . $envPath); } $lines = file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $config = []; foreach ($lines as $line) { $line = trim($line); if ($line === '' || strpos($line, '#') === 0) { continue; } if (strpos($line, '=') !== false) { list($key, $value) = explode('=', $line, 2); $config[trim($key)] = trim($value); } } $required = ['DB_HOST', 'DB_PORT', 'DB_USER', 'DB_PASSWORD', 'DB_NAME']; foreach ($required as $key) { if (!isset($config[$key]) || $config[$key] === '') { throw new RuntimeException("缺少必要的数据库配置: {$key}"); } } return $config; } /** * 检测数据库当前版本 */ function detectCurrentVersion($pdo) { try { $stmt = $pdo->query("SELECT setting_value FROM system_settings WHERE setting_key = 'db_version'"); $row = $stmt->fetch(PDO::FETCH_ASSOC); return $row ? $row['setting_value'] : '0.0.0'; } catch (PDOException $e) { return '0.0.0'; } } /** * 获取需要执行的升级步骤 */ function getUpgradeSteps($currentVersion, $targetVersion) { global $UPGRADE_VERSIONS; $steps = []; foreach ($UPGRADE_VERSIONS as $version => $sqlFile) { if (version_compare($version, $currentVersion, '>') && version_compare($version, $targetVersion, '<=')) { $steps[$version] = $sqlFile; } } uksort($steps, 'version_compare'); return $steps; } /** * 执行单个版本的升级 SQL */ function executeUpgrade($pdo, $version, $sqlFile) { if (!file_exists($sqlFile)) { throw new RuntimeException("SQL 文件不存在: {$sqlFile}"); } $sql = file_get_contents($sqlFile); if (trim($sql) === '' || trim($sql) === '--') { // 空文件或纯注释,无需执行 SQL,仅更新版本号 } else { $pdo->exec($sql); } // 更新版本号(使用预处理语句防止 SQL 注入) $stmt = $pdo->prepare( "INSERT INTO system_settings (setting_key, setting_value) VALUES ('db_version', :version) ON DUPLICATE KEY UPDATE setting_value = :version" ); $stmt->execute([':version' => $version]); } // =========================================== // 主逻辑 // =========================================== // POST 模式:执行单个升级步骤(依次执行) if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_GET['action'] ?? '') === 'step') { header('Content-Type: application/json; charset=utf-8'); $stepVersion = $_GET['version'] ?? ''; if (empty($stepVersion)) { http_response_code(400); echo json_encode(['success' => false, 'error' => '缺少版本号参数']); exit(); } try { $envPath = __DIR__ . '/backend/.env'; $config = readEnvConfig($envPath); $dsn = "mysql:host={$config['DB_HOST']};port={$config['DB_PORT']};dbname={$config['DB_NAME']};charset=utf8mb4"; $pdo = new PDO($dsn, $config['DB_USER'], $config['DB_PASSWORD'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); // 获取该版本对应的 SQL 文件 if (!isset($UPGRADE_VERSIONS[$stepVersion])) { throw new RuntimeException("未知版本: {$stepVersion}"); } $sqlFile = $UPGRADE_VERSIONS[$stepVersion]; $shortFile = basename($sqlFile); executeUpgrade($pdo, $stepVersion, $sqlFile); // 重新检测当前版本 $newVersion = detectCurrentVersion($pdo); echo json_encode([ 'success' => true, 'version' => $stepVersion, 'message' => "升级至 v{$stepVersion} 成功 ({$shortFile})", 'current' => $newVersion ]); } catch (Exception $e) { http_response_code(500); echo json_encode([ 'success' => false, 'version' => $stepVersion, 'error' => "升级至 v{$stepVersion} 失败: " . $e->getMessage() ]); } exit(); } // POST 模式:执行升级(AJAX 请求) if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_GET['action'] ?? '') === 'execute') { header('Content-Type: application/json; charset=utf-8'); $upgradeLog = []; $currentVersion = '未知'; $targetVersion = '未知'; try { $envPath = __DIR__ . '/backend/.env'; $config = readEnvConfig($envPath); $dsn = "mysql:host={$config['DB_HOST']};port={$config['DB_PORT']};dbname={$config['DB_NAME']};charset=utf8mb4"; $pdo = new PDO($dsn, $config['DB_USER'], $config['DB_PASSWORD'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $currentVersion = detectCurrentVersion($pdo); $versionFile = __DIR__ . '/VERSION'; if (!file_exists($versionFile)) { throw new RuntimeException('VERSION 文件不存在'); } $targetVersion = trim(file_get_contents($versionFile)); $upgradeSteps = getUpgradeSteps($currentVersion, $targetVersion); if (empty($upgradeSteps)) { echo json_encode([ 'success' => true, 'current' => $currentVersion, 'target' => $targetVersion, 'steps' => [['version' => '', 'status' => 'uptodate', 'message' => '数据库已是最新版本,无需升级。']] ]); exit(); } $pdo->beginTransaction(); try { foreach ($upgradeSteps as $version => $sqlFile) { $shortFile = basename($sqlFile); try { executeUpgrade($pdo, $version, $sqlFile); $upgradeLog[] = [ 'version' => $version, 'status' => 'success', 'message' => "升级至 v{$version} 成功 ({$shortFile})" ]; } catch (Exception $e) { $upgradeLog[] = [ 'version' => $version, 'status' => 'error', 'message' => "升级至 v{$version} 失败 ({$shortFile}): " . $e->getMessage() ]; throw $e; } } $pdo->commit(); } catch (Exception $e) { $pdo->rollBack(); throw $e; } echo json_encode([ 'success' => true, 'current' => $currentVersion, 'target' => $targetVersion, 'steps' => $upgradeLog ]); } catch (Exception $e) { http_response_code(500); echo json_encode([ 'success' => false, 'current' => $currentVersion, 'target' => $targetVersion, 'steps' => $upgradeLog, 'error' => $e->getMessage() ]); } exit(); } // GET 模式:显示升级信息页面 $currentVersion = '未知'; $targetVersion = '未知'; $upgradeSteps = []; $hasError = false; $errorMessage = ''; $isUpToDate = false; try { $envPath = __DIR__ . '/backend/.env'; $config = readEnvConfig($envPath); $dsn = "mysql:host={$config['DB_HOST']};port={$config['DB_PORT']};dbname={$config['DB_NAME']};charset=utf8mb4"; $pdo = new PDO($dsn, $config['DB_USER'], $config['DB_PASSWORD'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $currentVersion = detectCurrentVersion($pdo); $versionFile = __DIR__ . '/VERSION'; if (!file_exists($versionFile)) { throw new RuntimeException('VERSION 文件不存在: ' . $versionFile); } $targetVersion = trim(file_get_contents($versionFile)); $upgradeSteps = getUpgradeSteps($currentVersion, $targetVersion); $isUpToDate = empty($upgradeSteps); } catch (Exception $e) { $hasError = true; $errorMessage = $e->getMessage(); } ?> 系统升级 - 班级操行分管理系统

班级操行分管理系统 - 数据库升级

自动检测版本并执行增量升级

当前数据库版本
目标版本
错误:
💡 解决方法:
1. 进入 backend/ 目录
2. 复制配置模板:cp .env.example .env
3. 编辑 .env 文件,填入实际的数据库连接信息
4. 刷新此页面
✓ 数据库已是最新版本,无需升级。
待执行升级步骤
$sqlFile): ?>
升级至 v ()
⚠️ 升级前请确保已备份数据库,升级过程中请勿关闭页面。