Files
FendxPHP/app/Controller/AdminController.php

462 lines
14 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
namespace App\Controller;
use Fendx\Core\Annotation\Controller;
use Fendx\Web\Annotation\GetRoute;
use Fendx\Web\Annotation\PostRoute;
use Fendx\Web\Request\Request;
use Fendx\Web\Response\Response;
use Fendx\Monitor\Service\MonitorService;
#[Controller('/admin')]
class AdminController
{
#[GetRoute('/dashboard')]
public function dashboard(): array
{
// 检查管理员权限
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
// 获取仪表盘数据
$health = MonitorService::getHealthStatus();
$metrics = MonitorService::getMetricsSummary();
$alerts = MonitorService::getActiveAlerts();
$errors = MonitorService::getErrors([], 10);
$dashboard = [
'overview' => [
'status' => $health['status'],
'uptime' => $metrics['system']['uptime'] ?? 0,
'memory_usage' => $metrics['system']['memory_usage'] ?? 0,
'cpu_usage' => $metrics['system']['cpu_usage'] ?? 0,
'active_alerts' => count($alerts)
],
'health' => $health,
'metrics' => $metrics,
'alerts' => array_slice($alerts, 0, 5),
'recent_errors' => array_slice($errors, 0, 10),
'timestamp' => microtime(true)
];
return Response::success($dashboard);
}
#[GetRoute('/system/info')]
public function systemInfo(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
$info = [
'php_version' => PHP_VERSION,
'php_sapi' => PHP_SAPI,
'os' => PHP_OS,
'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'upload_max_filesize' => ini_get('upload_max_filesize'),
'post_max_size' => ini_get('post_max_size'),
'timezone' => date_default_timezone_get(),
'loaded_extensions' => get_loaded_extensions(),
'process_id' => getmypid(),
'hostname' => gethostname() ?? 'unknown'
];
return Response::success($info);
}
#[GetRoute('/system/status')]
public function systemStatus(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
$status = [
'timestamp' => microtime(true),
'uptime' => $this->getUptime(),
'memory' => [
'usage' => memory_get_usage(true),
'peak' => memory_get_peak_usage(true),
'limit' => $this->parseMemoryLimit(ini_get('memory_limit')),
'usage_percent' => $this->getMemoryUsagePercent()
],
'cpu' => [
'load_average' => function_exists('sys_getloadavg') ? sys_getloadavg() : null,
'usage' => $this->getCpuUsage()
],
'disk' => $this->getDiskUsage(),
'network' => $this->getNetworkInfo(),
'processes' => $this->getProcessInfo()
];
return Response::success($status);
}
#[GetRoute('/config')]
public function getConfig(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
// 获取监控配置(隐藏敏感信息)
$config = include dirname(__DIR__, 2) . '/config/config.php';
$safeConfig = [
'monitor' => $config['monitor'] ?? [],
'database' => [
'driver' => $config['database']['driver'] ?? 'unknown',
'host' => $config['database']['host'] ?? 'unknown',
'database' => $config['database']['database'] ?? 'unknown'
],
'cache' => [
'driver' => $config['cache']['driver'] ?? 'unknown'
]
];
return Response::success($safeConfig);
}
#[PostRoute('/config')]
public function updateConfig(Request $request): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
$data = $request->all();
// 验证配置数据
$validation = $this->validateConfig($data);
if (!$validation['valid']) {
return Response::error(400, 'Invalid config: ' . implode(', ', $validation['errors']));
}
// 这里应该更新配置文件
// 为了安全,实际项目中应该有更严格的配置管理
return Response::success(null, 'Configuration updated successfully');
}
#[PostRoute('/cache/clear')]
public function clearCache(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
try {
// 清理应用缓存
$cacheDir = dirname(__DIR__, 2) . '/runtime/cache';
if (is_dir($cacheDir)) {
$this->clearDirectory($cacheDir);
}
// 清理模板缓存
$templateDir = dirname(__DIR__, 2) . '/runtime/templates';
if (is_dir($templateDir)) {
$this->clearDirectory($templateDir);
}
return Response::success(null, 'Cache cleared successfully');
} catch (\Exception $e) {
return Response::error(500, 'Failed to clear cache: ' . $e->getMessage());
}
}
#[PostRoute('/logs/clear')]
public function clearLogs(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
try {
$logDir = dirname(__DIR__, 2) . '/runtime/logs';
if (is_dir($logDir)) {
$this->clearDirectory($logDir, ['.gitkeep']);
}
return Response::success(null, 'Logs cleared successfully');
} catch (\Exception $e) {
return Response::error(500, 'Failed to clear logs: ' . $e->getMessage());
}
}
#[GetRoute('/users')]
public function getUsers(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
// 这里应该从数据库获取用户列表
// 暂时返回模拟数据
$users = [
['id' => 1, 'username' => 'admin', 'email' => 'admin@example.com', 'role' => 'admin', 'status' => 'active', 'created_at' => '2024-01-01 00:00:00'],
['id' => 2, 'username' => 'user1', 'email' => 'user1@example.com', 'role' => 'user', 'status' => 'active', 'created_at' => '2024-01-02 00:00:00']
];
return Response::success($users);
}
#[PostRoute('/users/{id}/ban')]
public function banUser(int $id): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
// 这里应该更新数据库中的用户状态
return Response::success(null, 'User banned successfully');
}
#[PostRoute('/users/{id}/unban')]
public function unbanUser(int $id): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
// 这里应该更新数据库中的用户状态
return Response::success(null, 'User unbanned successfully');
}
#[GetRoute('/permissions')]
public function getPermissions(): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
$permissions = [
'dashboard' => ['view'],
'monitor' => ['view', 'manage'],
'logs' => ['view', 'search', 'export'],
'alerts' => ['view', 'acknowledge', 'resolve'],
'users' => ['view', 'manage'],
'config' => ['view', 'edit'],
'system' => ['view', 'cache_clear', 'logs_clear']
];
return Response::success($permissions);
}
#[GetRoute('/audit')]
public function getAuditLogs(Request $request): array
{
if (!$this->checkAdminPermission()) {
return Response::error(403, 'Permission denied');
}
$limit = (int)($request->get('limit', 50));
$offset = (int)($request->get('offset', 0));
$userId = $request->get('user_id');
$action = $request->get('action');
// 这里应该从数据库获取审计日志
// 暂时返回模拟数据
$logs = [
[
'id' => 1,
'user_id' => 1,
'username' => 'admin',
'action' => 'login',
'resource' => 'admin',
'ip' => '127.0.0.1',
'user_agent' => 'Mozilla/5.0...',
'created_at' => '2024-01-01 12:00:00'
],
[
'id' => 2,
'user_id' => 1,
'username' => 'admin',
'action' => 'config_update',
'resource' => 'monitor',
'ip' => '127.0.0.1',
'user_agent' => 'Mozilla/5.0...',
'created_at' => '2024-01-01 12:30:00'
]
];
return Response::success([
'logs' => $logs,
'total' => count($logs),
'limit' => $limit,
'offset' => $offset
]);
}
private function checkAdminPermission(): bool
{
// 这里应该实现实际的权限检查
// 可以检查用户角色、session、token等
// 简单示例检查是否有admin session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
return isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin';
}
private function getUptime(): int
{
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
return $load[0] ?? 0;
}
// 尝试从/proc/uptime读取Linux
if (file_exists('/proc/uptime')) {
$uptime = file_get_contents('/proc/uptime');
return (int)explode(' ', $uptime)[0];
}
return 0;
}
private function parseMemoryLimit(string $limit): int
{
if ($limit === '-1') {
return -1;
}
$unit = strtoupper(substr($limit, -1));
$value = (int)substr($limit, 0, -1);
return match ($unit) {
'G' => $value * 1024 * 1024 * 1024,
'M' => $value * 1024 * 1024,
'K' => $value * 1024,
default => (int)$limit
};
}
private function getMemoryUsagePercent(): float
{
$usage = memory_get_usage(true);
$limit = $this->parseMemoryLimit(ini_get('memory_limit'));
if ($limit <= 0) {
return 0;
}
return ($usage / $limit) * 100;
}
private function getCpuUsage(): float
{
// 简单的CPU使用率计算
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
return $load[0] ?? 0;
}
return 0;
}
private function getDiskUsage(): array
{
$paths = [
'root' => dirname(__DIR__, 2),
'runtime' => dirname(__DIR__, 2) . '/runtime'
];
$usage = [];
foreach ($paths as $name => $path) {
if (file_exists($path)) {
$free = disk_free_space($path);
$total = disk_total_space($path);
$used = $total - $free;
$usage[$name] = [
'path' => $path,
'total' => $total,
'used' => $used,
'free' => $free,
'usage_percent' => ($used / $total) * 100
];
}
}
return $usage;
}
private function getNetworkInfo(): array
{
return [
'hostname' => gethostname() ?? 'unknown',
'ip' => $_SERVER['SERVER_ADDR'] ?? '127.0.0.1',
'port' => $_SERVER['SERVER_PORT'] ?? 80,
'scheme' => $_SERVER['REQUEST_SCHEME'] ?? 'http'
];
}
private function getProcessInfo(): array
{
return [
'pid' => getmypid(),
'memory_usage' => memory_get_usage(true),
'memory_peak' => memory_get_peak_usage(true),
'included_files' => count(get_included_files()),
'classes' => count(get_declared_classes()),
'functions' => count(get_defined_functions()['user'])
];
}
private function validateConfig(array $data): array
{
$errors = [];
if (isset($data['sample_rate']) && ($data['sample_rate'] < 0 || $data['sample_rate'] > 1)) {
$errors[] = 'Sample rate must be between 0 and 1';
}
if (isset($data['retention']) && $data['retention'] < 0) {
$errors[] = 'Retention period must be positive';
}
if (isset($data['error_threshold']) && ($data['error_threshold'] < 0 || $data['error_threshold'] > 1)) {
$errors[] = 'Error threshold must be between 0 and 1';
}
if (isset($data['memory_threshold']) && ($data['memory_threshold'] < 0 || $data['memory_threshold'] > 1)) {
$errors[] = 'Memory threshold must be between 0 and 1';
}
return [
'valid' => empty($errors),
'errors' => $errors
];
}
private function clearDirectory(string $dir, array $exclude = []): void
{
if (!is_dir($dir)) {
return;
}
$files = scandir($dir);
foreach ($files as $file) {
if ($file === '.' || $file === '..' || in_array($file, $exclude)) {
continue;
}
$path = $dir . DIRECTORY_SEPARATOR . $file;
if (is_dir($path)) {
$this->clearDirectory($path);
rmdir($path);
} else {
unlink($path);
}
}
}
}