loadConfig(); $this->connectDatabase(); } /** * 加载配置 */ private function loadConfig(): void { // 加载环境配置 $envFile = __DIR__ . '/../.env'; if (file_exists($envFile)) { $lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($lines as $line) { if (strpos($line, '=') !== false) { list($key, $value) = explode('=', $line, 2); $_ENV[trim($key)] = trim($value); $_SERVER[trim($key)] = trim($value); } } } $this->config = [ 'host' => $_ENV['DB_HOST'] ?? 'localhost', 'port' => $_ENV['DB_PORT'] ?? '3306', 'database' => $_ENV['DB_DATABASE'] ?? 'fendx_php', 'username' => $_ENV['DB_USERNAME'] ?? 'root', 'password' => $_ENV['DB_PASSWORD'] ?? '', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', ]; } /** * 连接数据库 */ private function connectDatabase(): void { try { $dsn = sprintf( 'mysql:host=%s;port=%s;charset=%s', $this->config['host'], $this->config['port'], $this->config['charset'] ); $this->pdo = new PDO($dsn, $this->config['username'], $this->config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); echo "✅ 数据库连接成功\n"; } catch (PDOException $e) { echo "❌ 数据库连接失败: " . $e->getMessage() . "\n"; exit(1); } } /** * 检查数据库是否存在 */ public function checkDatabaseExists(): bool { try { $stmt = $this->pdo->query("SHOW DATABASES LIKE '{$this->config['database']}'"); $result = $stmt->fetch(); if ($result) { echo "✅ 数据库 '{$this->config['database']}' 存在\n"; return true; } else { echo "❌ 数据库 '{$this->config['database']}' 不存在\n"; return false; } } catch (PDOException $e) { echo "❌ 检查数据库失败: " . $e->getMessage() . "\n"; return false; } } /** * 创建数据库 */ public function createDatabase(): bool { try { $sql = sprintf( "CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET %s COLLATE %s", $this->config['database'], $this->config['charset'], $this->config['collation'] ); $this->pdo->exec($sql); echo "✅ 数据库 '{$this->config['database']}' 创建成功\n"; return true; } catch (PDOException $e) { echo "❌ 创建数据库失败: " . $e->getMessage() . "\n"; return false; } } /** * 选择数据库 */ private function selectDatabase(): bool { try { $this->pdo->exec("USE `{$this->config['database']}`"); return true; } catch (PDOException $e) { echo "❌ 选择数据库失败: " . $e->getMessage() . "\n"; return false; } } /** * 检查表结构 */ public function checkTables(): array { if (!$this->selectDatabase()) { return []; } try { $stmt = $this->pdo->query("SHOW TABLES"); $tables = $stmt->fetchAll(PDO::FETCH_COLUMN); if (empty($tables)) { echo "⚠️ 数据库中没有表\n"; return []; } echo "📊 数据库表列表:\n"; foreach ($tables as $table) { $count = $this->getTableRecordCount($table); echo " - {$table} ({$count} 条记录)\n"; } return $tables; } catch (PDOException $e) { echo "❌ 检查表失败: " . $e->getMessage() . "\n"; return []; } } /** * 获取表记录数 */ private function getTableRecordCount(string $table): int { try { $stmt = $this->pdo->query("SELECT COUNT(*) FROM `{$table}`"); return (int) $stmt->fetchColumn(); } catch (PDOException $e) { return 0; } } /** * 检查迁移表 */ public function checkMigrations(): void { if (!$this->selectDatabase()) { return; } try { // 检查迁移表是否存在 $stmt = $this->pdo->query("SHOW TABLES LIKE 'migrations'"); $hasMigrationsTable = $stmt->fetch() !== false; if (!$hasMigrationsTable) { echo "⚠️ 迁移表不存在,需要运行迁移\n"; return; } // 检查迁移记录 $stmt = $this->pdo->query("SELECT * FROM migrations ORDER BY id DESC LIMIT 10"); $migrations = $stmt->fetchAll(); if (empty($migrations)) { echo "⚠️ 没有迁移记录\n"; return; } echo "📋 最近迁移记录:\n"; foreach ($migrations as $migration) { echo " - {$migration['migration']} ({$migration['batch']})\n"; } } catch (PDOException $e) { echo "❌ 检查迁移失败: " . $e->getMessage() . "\n"; } } /** * 检查用户表数据 */ public function checkUserData(): void { if (!$this->selectDatabase()) { return; } try { // 检查用户表是否存在 $stmt = $this->pdo->query("SHOW TABLES LIKE 'users'"); if (!$stmt->fetch()) { echo "⚠️ 用户表不存在\n"; return; } // 检查用户数据 $stmt = $this->pdo->query("SELECT COUNT(*) FROM users"); $userCount = $stmt->fetchColumn(); echo "👥 用户数据:\n"; echo " - 总用户数: {$userCount}\n"; if ($userCount > 0) { // 显示最近注册的用户 $stmt = $this->pdo->query("SELECT id, username, email, created_at FROM users ORDER BY created_at DESC LIMIT 5"); $recentUsers = $stmt->fetchAll(); echo " - 最近注册用户:\n"; foreach ($recentUsers as $user) { echo " * {$user['username']} ({$user['email']}) - {$user['created_at']}\n"; } } } catch (PDOException $e) { echo "❌ 检查用户数据失败: " . $e->getMessage() . "\n"; } } /** * 测试数据库权限 */ public function testPermissions(): void { echo "🔐 测试数据库权限:\n"; // 测试SELECT权限 try { $this->pdo->query("SELECT 1"); echo " ✅ SELECT 权限正常\n"; } catch (PDOException $e) { echo " ❌ SELECT 权限失败: " . $e->getMessage() . "\n"; } // 测试INSERT权限 try { $this->pdo->exec("CREATE TABLE IF NOT EXISTS test_permissions (id INT)"); $this->pdo->exec("INSERT INTO test_permissions (id) VALUES (1)"); $this->pdo->exec("DROP TABLE test_permissions"); echo " ✅ INSERT 权限正常\n"; } catch (PDOException $e) { echo " ❌ INSERT 权限失败: " . $e->getMessage() . "\n"; } // 测试CREATE权限 try { $this->pdo->exec("CREATE TABLE IF NOT EXISTS test_create (id INT)"); $this->pdo->exec("DROP TABLE test_create"); echo " ✅ CREATE 权限正常\n"; } catch (PDOException $e) { echo " ❌ CREATE 权限失败: " . $e->getMessage() . "\n"; } } /** * 检查数据库连接池状态 */ public function checkConnectionPool(): void { echo "🔗 检查连接池状态:\n"; // 模拟多个连接 $connections = []; $successCount = 0; for ($i = 0; $i < 5; $i++) { try { $dsn = sprintf( 'mysql:host=%s;port=%s;charset=%s', $this->config['host'], $this->config['port'], $this->config['charset'] ); $pdo = new PDO($dsn, $this->config['username'], $this->config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); $pdo->query("SELECT 1"); $connections[] = $pdo; $successCount++; } catch (PDOException $e) { echo " ❌ 连接 {$i} 失败: " . $e->getMessage() . "\n"; } } echo " ✅ 成功建立 {$successCount}/5 个连接\n"; // 关闭连接 foreach ($connections as $pdo) { $pdo = null; } } /** * 运行完整检查 */ public function runFullCheck(): void { echo "🔍 开始数据库完整检查...\n"; echo str_repeat("=", 50) . "\n"; // 显示配置信息 echo "📋 数据库配置:\n"; echo " - 主机: {$this->config['host']}\n"; echo " - 端口: {$this->config['port']}\n"; echo " - 数据库: {$this->config['database']}\n"; echo " - 用户名: {$this->config['username']}\n"; echo " - 字符集: {$this->config['charset']}\n"; echo str_repeat("-", 50) . "\n"; // 检查数据库是否存在 if (!$this->checkDatabaseExists()) { echo "🔧 尝试创建数据库...\n"; if ($this->createDatabase()) { echo "✅ 数据库创建成功\n"; } else { echo "❌ 数据库创建失败,请检查权限\n"; return; } } // 检查表结构 $this->checkTables(); echo str_repeat("-", 50) . "\n"; // 检查迁移 $this->checkMigrations(); echo str_repeat("-", 50) . "\n"; // 检查用户数据 $this->checkUserData(); echo str_repeat("-", 50) . "\n"; // 测试权限 $this->testPermissions(); echo str_repeat("-", 50) . "\n"; // 检查连接池 $this->checkConnectionPool(); echo str_repeat("=", 50) . "\n"; echo "✅ 数据库检查完成\n"; } /** * 修复数据库 */ public function repairDatabase(): void { echo "🔧 开始修复数据库...\n"; // 创建数据库 if (!$this->checkDatabaseExists()) { $this->createDatabase(); } // 选择数据库 if (!$this->selectDatabase()) { echo "❌ 无法选择数据库\n"; return; } // 运行迁移 echo "🔄 运行数据库迁移...\n"; $migrateCommand = "php bin/console migrate:run"; echo "执行: {$migrateCommand}\n"; system($migrateCommand); // 填充测试数据 echo "🌱 填充测试数据...\n"; $seedCommand = "php bin/console migrate:seed"; echo "执行: {$seedCommand}\n"; system($seedCommand); echo "✅ 数据库修复完成\n"; } } // 主程序 function main(): void { $options = getopt('cfr', ['check', 'fix', 'repair', 'help']); if (isset($options['h']) || isset($options['help'])) { echo "数据库检查工具\n"; echo "用法: php scripts/check-database.php [选项]\n"; echo "\n选项:\n"; echo " -c, --check 检查数据库状态 (默认)\n"; echo " -f, --fix 修复数据库问题\n"; echo " -r, --repair 修复数据库 (同 --fix)\n"; echo " -h, --help 显示帮助信息\n"; echo "\n示例:\n"; echo " php scripts/check-database.php # 检查数据库\n"; echo " php scripts/check-database.php --check # 检查数据库\n"; echo " php scripts/check-database.php --fix # 修复数据库\n"; return; } try { $checker = new DatabaseChecker(); if (isset($options['f']) || isset($options['fix']) || isset($options['r']) || isset($options['repair'])) { $checker->repairDatabase(); } else { $checker->runFullCheck(); } } catch (Exception $e) { echo "❌ 检查失败: " . $e->getMessage() . "\n"; exit(1); } } // 运行主程序 main();