mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 15:02:49 +08:00
- 创建用户表(users)包含基本信息和认证字段 - 创建角色表(roles)用于权限控制 - 创建权限表(permissions)定义系统权限 - 创建用户角色关联表(user_roles)建立用户与角色关系 - 创建角色权限关联表(role_permissions)建立角色与权限关系 - 创建迁移记录表(migrations)追踪数据库变更 - 添加AdminController提供管理员面板功能 - 实现系统监控、配置管理、缓存清理等功能 - 添加AOP切面编程支持的各种通知类型 - 实现告警管理AlertManager支持多渠道告警 - 添加文档注解接口规范
454 lines
13 KiB
PHP
454 lines
13 KiB
PHP
<?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();
|