chore: complete update
This commit is contained in:
340
src/Application/Admin/Dashboard.php
Normal file
340
src/Application/Admin/Dashboard.php
Normal file
@@ -0,0 +1,340 @@
|
||||
<?php
|
||||
|
||||
namespace App\Application\Admin;
|
||||
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\Auth\Auth;
|
||||
use App\Framework\Config\TypedConfiguration;
|
||||
use App\Framework\Core\VersionInfo;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\Http\HttpResponse;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Meta\MetaData;
|
||||
use App\Framework\Meta\OpenGraphTypeWebsite;
|
||||
use App\Framework\Performance\MemoryUsageTracker;
|
||||
use App\Framework\Router\Result\ViewResult;
|
||||
use App\Framework\Http\Session\SessionManager;
|
||||
use App\Framework\Http\Status;
|
||||
use Dom\HTMLDocument;
|
||||
|
||||
final readonly class Dashboard
|
||||
{
|
||||
public function __construct(
|
||||
private DefaultContainer $container,
|
||||
private VersionInfo $versionInfo,
|
||||
private MemoryUsageTracker $memoryTracker,
|
||||
private TypedConfiguration $config,
|
||||
) {}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin', method: Method::GET)]
|
||||
public function show(): ViewResult
|
||||
{
|
||||
$stats = [
|
||||
'frameworkVersion' => $this->versionInfo->getVersion(),
|
||||
'phpVersion' => PHP_VERSION,
|
||||
'memoryUsage' => $this->formatBytes(memory_get_usage(true)),
|
||||
'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
|
||||
'serverInfo' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
|
||||
'serverTime' => date('Y-m-d H:i:s'),
|
||||
'timezone' => date_default_timezone_get(),
|
||||
'operatingSystem' => PHP_OS,
|
||||
'loadedExtensions' => $this->getLoadedExtensions(),
|
||||
'sessionCount' => $this->getActiveSessionCount(),
|
||||
'uptime' => $this->getServerUptime(),
|
||||
'servicesCount' => 4,#count($this->container->getServiceIds()),
|
||||
];
|
||||
|
||||
#debug($stats);
|
||||
|
||||
return new ViewResult(
|
||||
template: 'dashboard',
|
||||
metaData: new MetaData('Admin Dashboard'),
|
||||
data: [
|
||||
'title' => 'Admin Dashboard',
|
||||
'stats' => $stats
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin/routes', method: Method::GET)]
|
||||
public function routes(): ViewResult
|
||||
{
|
||||
$routeRegistry = $this->container->get('App\Framework\Router\RouteRegistry');
|
||||
$routes = $routeRegistry->getRoutes();
|
||||
|
||||
// Sort routes by path for better readability
|
||||
usort($routes, function($a, $b) {
|
||||
return strcmp($a->path, $b->path);
|
||||
});
|
||||
|
||||
return new ViewResult(
|
||||
template: 'admin/routes',
|
||||
metaData: new MetaData('', ''),
|
||||
data: [
|
||||
'title' => 'Routen-Übersicht',
|
||||
'routes' => $routes
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin/services', method: Method::GET)]
|
||||
public function services(): ViewResult
|
||||
{
|
||||
$services = $this->container->getServiceIds();
|
||||
sort($services);
|
||||
|
||||
return new ViewResult(
|
||||
template: 'admin/services',
|
||||
data: [
|
||||
'title' => 'Registrierte Dienste',
|
||||
'services' => $services
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin/environment', method: Method::GET)]
|
||||
public function environment(): ViewResult
|
||||
{
|
||||
$env = [];
|
||||
foreach ($_ENV as $key => $value) {
|
||||
// Maskiere sensible Daten
|
||||
if (str_contains(strtolower($key), 'password') ||
|
||||
str_contains(strtolower($key), 'secret') ||
|
||||
str_contains(strtolower($key), 'key')) {
|
||||
$value = '********';
|
||||
}
|
||||
$env[$key] = $value;
|
||||
}
|
||||
|
||||
ksort($env);
|
||||
|
||||
dd($env);
|
||||
|
||||
return new ViewResult(
|
||||
template: 'admin/environment',
|
||||
metaData: new MetaData('', ''),
|
||||
data: [
|
||||
'title' => 'Umgebungsvariablen',
|
||||
'env' => $env
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route('/admin/phpinfo')]
|
||||
#[Route(path: '/admin/phpinfo/{mode}', method: Method::GET)]
|
||||
public function phpInfo(int $mode = 1): Response
|
||||
{
|
||||
ob_start();
|
||||
phpinfo($mode);
|
||||
$phpinfo = ob_get_clean();
|
||||
|
||||
// Extraktion des <body> Inhalts, um nur den relevanten Teil anzuzeigen
|
||||
preg_match('/<body[^>]*>(.*?)<\/body>/si', $phpinfo, $matches);
|
||||
$body = $matches[1] ?? $phpinfo;
|
||||
|
||||
// Entfernen der Navigation-Links am Anfang
|
||||
#$body = preg_replace('/<div class="center">(.*?)<\/div>/si', '', $body, 1);
|
||||
|
||||
#debug($body);
|
||||
|
||||
// Hinzufügen von eigenen Styles
|
||||
$customStyles = '<style>
|
||||
.phpinfo { font-family: system-ui, sans-serif; line-height: 1.5; }
|
||||
.phpinfo table { border-collapse: collapse; width: 100%; margin-bottom: 1rem; }
|
||||
.phpinfo td, .phpinfo th { padding: 0.5rem; border: 1px solid #ddd; }
|
||||
.phpinfo h1, .phpinfo h2 { margin-bottom: 1rem; }
|
||||
.phpinfo hr { margin: 2rem 0; }
|
||||
</style>';
|
||||
|
||||
$responseBody = '<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PHP Info</title>
|
||||
<link rel="stylesheet" href="/css/admin.css">
|
||||
' . $customStyles . '
|
||||
</head>
|
||||
<body class="admin-page">
|
||||
<div class="admin-header">
|
||||
<h1>PHP Info</h1>
|
||||
<a href="/admin" class="btn">Zurück zum Dashboard</a>
|
||||
</div>
|
||||
<div class="admin-content">
|
||||
<div class="phpinfo">' . $body . '</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
echo $responseBody;
|
||||
die();
|
||||
|
||||
return new HttpResponse(status: Status::OK, body: $responseBody);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin/performance', method: Method::GET)]
|
||||
public function performance(): ViewResult
|
||||
{
|
||||
$performanceData = [
|
||||
'currentMemoryUsage' => $this->formatBytes(memory_get_usage(true)),
|
||||
'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
|
||||
'memoryLimit' => $this->formatBytes($this->getMemoryLimitInBytes()),
|
||||
'memoryUsagePercentage' => round((memory_get_usage(true) / $this->getMemoryLimitInBytes()) * 100, 2),
|
||||
'loadAverage' => function_exists('sys_getloadavg') ? sys_getloadavg() : ['N/A', 'N/A', 'N/A'],
|
||||
'opcacheEnabled' => function_exists('opcache_get_status') ? 'Ja' : 'Nein',
|
||||
'executionTime' => number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 4) . ' Sekunden',
|
||||
'includedFiles' => count(get_included_files()),
|
||||
];
|
||||
|
||||
if (function_exists('opcache_get_status')) {
|
||||
try {
|
||||
$opcacheStatus = opcache_get_status(false);
|
||||
if ($opcacheStatus !== false) {
|
||||
$performanceData['opcacheMemoryUsage'] = $this->formatBytes($opcacheStatus['memory_usage']['used_memory']);
|
||||
$performanceData['opcacheCacheHits'] = number_format($opcacheStatus['opcache_statistics']['hits']);
|
||||
$performanceData['opcacheMissRate'] = number_format($opcacheStatus['opcache_statistics']['misses'] /
|
||||
($opcacheStatus['opcache_statistics']['hits'] + $opcacheStatus['opcache_statistics']['misses']) * 100, 2) . '%';
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// OPCache Status konnte nicht abgerufen werden
|
||||
$performanceData['opcacheError'] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return new ViewResult(
|
||||
template: 'performance',
|
||||
data: [
|
||||
'title' => 'Performance-Daten',
|
||||
'performance' => $performanceData
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Auth]
|
||||
#[Route(path: '/admin/redis', method: Method::GET)]
|
||||
public function redisInfo(): ViewResult
|
||||
{
|
||||
$redisInfo = [];
|
||||
|
||||
try {
|
||||
$redis = $this->container->get('Predis\Client');
|
||||
$info = $redis->info();
|
||||
$redisInfo['status'] = 'Verbunden';
|
||||
$redisInfo['version'] = $info['redis_version'];
|
||||
$redisInfo['uptime'] = $this->formatUptime((int)$info['uptime_in_seconds']);
|
||||
$redisInfo['memory'] = $this->formatBytes((int)$info['used_memory']);
|
||||
$redisInfo['peak_memory'] = $this->formatBytes((int)$info['used_memory_peak']);
|
||||
$redisInfo['clients'] = $info['connected_clients'];
|
||||
$redisInfo['keys'] = $redis->dbsize();
|
||||
|
||||
// Einige Schlüssel auflisten (begrenzt auf 50)
|
||||
$keys = $redis->keys('*');
|
||||
$redisInfo['key_sample'] = array_slice($keys, 0, 50);
|
||||
} catch (\Throwable $e) {
|
||||
$redisInfo['status'] = 'Fehler: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return new ViewResult(
|
||||
template: 'admin/redis',
|
||||
data: [
|
||||
'title' => 'Redis Information',
|
||||
'redis' => $redisInfo
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function formatBytes(int $bytes, int $precision = 2): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
|
||||
private function getMemoryLimitInBytes(): int
|
||||
{
|
||||
$memoryLimit = ini_get('memory_limit');
|
||||
|
||||
if ($memoryLimit === '-1') {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$value = (int) $memoryLimit;
|
||||
$unit = strtolower($memoryLimit[strlen($memoryLimit)-1]);
|
||||
|
||||
switch($unit) {
|
||||
case 'g':
|
||||
$value *= 1024;
|
||||
case 'm':
|
||||
$value *= 1024;
|
||||
case 'k':
|
||||
$value *= 1024;
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function getLoadedExtensions(): array
|
||||
{
|
||||
$extensions = get_loaded_extensions();
|
||||
sort($extensions);
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
private function getActiveSessionCount(): int
|
||||
{
|
||||
try {
|
||||
if ($this->container->has(SessionManager::class)) {
|
||||
$sessionManager = $this->container->get(SessionManager::class);
|
||||
// Diese Methode müsste implementiert werden
|
||||
return $sessionManager->getActiveSessionCount();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Silent fail
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getServerUptime(): string
|
||||
{
|
||||
// Für Linux-Systeme
|
||||
if (function_exists('shell_exec') && stripos(PHP_OS, 'Linux') !== false) {
|
||||
$uptime = shell_exec('uptime -p');
|
||||
if ($uptime) {
|
||||
return $uptime;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return 'Nicht verfügbar';
|
||||
}
|
||||
|
||||
private function formatUptime(int $seconds): string
|
||||
{
|
||||
$days = floor($seconds / 86400);
|
||||
$hours = floor(($seconds % 86400) / 3600);
|
||||
$minutes = floor(($seconds % 3600) / 60);
|
||||
$remainingSeconds = $seconds % 60;
|
||||
|
||||
$result = '';
|
||||
if ($days > 0) {
|
||||
$result .= "$days Tage, ";
|
||||
}
|
||||
|
||||
return $result . sprintf('%02d:%02d:%02d', $hours, $minutes, $remainingSeconds);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user