Files
FendxPHP/scripts/check-database.php

454 lines
13 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
/**
* 数据库状态检查脚本
* 用法: php scripts/check-database.php [options]
*/
use Fendx\Db\DB;
use Fendx\Core\Config\Config;
class DatabaseChecker
{
private array $config;
private ?PDO $pdo = null;
public function __construct()
{
$this->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();