Newwebshop/controllers/admin/PerformanceController.php

525 lines
16 KiB
PHP

<?php
/**
* Copyright seit 2024 Webshop System
*
* Admin Performance Controller für das Webshop-System
*
* @author Webshop System
* @license GPL v3
*/
namespace App\Controllers\Admin;
use App\Core\Performance;
use App\Core\Cache;
use App\Core\Session;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception;
class PerformanceController
{
private $performance;
private $cache;
private $session;
public function __construct()
{
$this->performance = new Performance();
$this->cache = new Cache();
$this->session = new Session();
// Session-Check für Admin
if (!$this->session->isLoggedIn() || !$this->session->isAdmin()) {
header('Location: /admin/login');
exit;
}
}
/**
* Performance-Dashboard anzeigen
*/
public function index()
{
$title = 'Performance-Monitoring - Webshop Admin';
// Performance-Header setzen
$this->performance->setPerformanceHeaders();
// Template rendern
$this->renderTemplate('admin/performance/index.html.twig', [
'title' => $title
]);
}
/**
* Performance-Statistiken API
*/
public function getStats()
{
header('Content-Type: application/json');
try {
$stats = $this->performance->getStats();
$cacheStats = $this->cache->getStats();
// Cache-Hit-Rate berechnen
$totalRequests = ($cacheStats['hits'] ?? 0) + ($cacheStats['misses'] ?? 0);
$hitRate = $totalRequests > 0 ? round(($cacheStats['hits'] ?? 0) / $totalRequests * 100, 2) : 0;
$response = [
'success' => true,
'data' => [
'execution_time' => $stats['execution_time'],
'memory_usage' => $stats['memory_usage'],
'queries_count' => $stats['queries_count'],
'cache_hit_rate' => $hitRate,
'cache_hits' => $cacheStats['hits'] ?? 0,
'cache_misses' => $cacheStats['misses'] ?? 0,
'cache_size' => $this->formatBytes($this->getCacheSize()),
'execution_time_labels' => $this->getExecutionTimeLabels(),
'execution_time_data' => $this->getExecutionTimeData(),
'memory_labels' => $this->getMemoryLabels(),
'memory_data' => $this->getMemoryData()
]
];
echo json_encode($response);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Failed to get performance stats: ' . $e->getMessage()
]);
}
}
/**
* Performance-Metriken API
*/
public function getMetrics()
{
header('Content-Type: application/json');
try {
$metrics = [
[
'name' => 'Datenbank-Verbindungen',
'description' => 'Aktive Datenbankverbindungen',
'value' => $this->getDatabaseConnections(),
'unit' => 'Verbindungen',
'percentage' => min(100, $this->getDatabaseConnections() / 10 * 100)
],
[
'name' => 'Cache-Effizienz',
'description' => 'Cache-Trefferrate',
'value' => $this->getCacheHitRate(),
'unit' => '%',
'percentage' => $this->getCacheHitRate()
],
[
'name' => 'Speicherverbrauch',
'description' => 'PHP Speicherverbrauch',
'value' => $this->formatBytes(memory_get_usage()),
'unit' => 'Bytes',
'percentage' => min(100, memory_get_usage() / (1024 * 1024 * 128) * 100)
],
[
'name' => 'Datenbank-Größe',
'description' => 'Gesamtgröße der Datenbank',
'value' => $this->getDatabaseSize(),
'unit' => 'MB',
'percentage' => min(100, $this->getDatabaseSize() / 1000 * 100)
],
[
'name' => 'Aktive Sessions',
'description' => 'Aktive Benutzer-Sessions',
'value' => $this->getActiveSessions(),
'unit' => 'Sessions',
'percentage' => min(100, $this->getActiveSessions() / 100 * 100)
],
[
'name' => 'Durchschnittliche Ladezeit',
'description' => 'Durchschnittliche Seitenladezeit',
'value' => $this->getAverageLoadTime(),
'unit' => 'ms',
'percentage' => min(100, $this->getAverageLoadTime() / 2000 * 100)
]
];
echo json_encode([
'success' => true,
'data' => $metrics
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Failed to get metrics: ' . $e->getMessage()
]);
}
}
/**
* Datenbank optimieren
*/
public function optimizeDatabase()
{
header('Content-Type: application/json');
try {
$result = $this->performance->optimizeDatabase();
if ($result) {
echo json_encode([
'success' => true,
'message' => 'Database optimized successfully'
]);
} else {
echo json_encode([
'success' => false,
'error' => 'Failed to optimize database'
]);
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Database optimization failed: ' . $e->getMessage()
]);
}
}
/**
* Cache leeren
*/
public function clearCache()
{
header('Content-Type: application/json');
try {
$result = $this->cache->clear();
echo json_encode([
'success' => true,
'message' => 'Cache cleared successfully',
'cleared_items' => $result
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Failed to clear cache: ' . $e->getMessage()
]);
}
}
/**
* Bilder optimieren
*/
public function optimizeImages()
{
header('Content-Type: application/json');
try {
$imageDir = __DIR__ . '/../../public/img/';
$optimizedCount = 0;
if (is_dir($imageDir)) {
$images = glob($imageDir . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);
foreach ($images as $image) {
$optimizedPath = str_replace(['.jpg', '.jpeg', '.png', '.gif'], '_optimized.jpg', $image);
if ($this->performance->optimizeImage($image, $optimizedPath, [
'quality' => 85,
'max_width' => 1200,
'max_height' => 1200,
'format' => 'jpeg'
])) {
$optimizedCount++;
}
}
}
echo json_encode([
'success' => true,
'message' => 'Images optimized successfully',
'optimized_count' => $optimizedCount
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Failed to optimize images: ' . $e->getMessage()
]);
}
}
/**
* Sitemap generieren
*/
public function generateSitemap()
{
header('Content-Type: application/json');
try {
$sitemap = $this->generateSitemapContent();
$sitemapPath = __DIR__ . '/../../public/sitemap.xml';
if (file_put_contents($sitemapPath, $sitemap)) {
echo json_encode([
'success' => true,
'message' => 'Sitemap generated successfully'
]);
} else {
echo json_encode([
'success' => false,
'error' => 'Failed to write sitemap file'
]);
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => 'Failed to generate sitemap: ' . $e->getMessage()
]);
}
}
/**
* Cache-Größe abrufen
*/
private function getCacheSize()
{
$cacheDir = __DIR__ . '/../../cache/';
if (!is_dir($cacheDir)) {
return 0;
}
$size = 0;
$files = glob($cacheDir . '*.cache');
foreach ($files as $file) {
$size += filesize($file);
}
return $size;
}
/**
* Ausführungszeit-Labels generieren
*/
private function getExecutionTimeLabels()
{
$labels = [];
for ($i = 23; $i >= 0; $i--) {
$labels[] = date('H:i', strtotime("-$i hours"));
}
return $labels;
}
/**
* Ausführungszeit-Daten generieren
*/
private function getExecutionTimeData()
{
// Simulierte Daten für Demo
$data = [];
for ($i = 0; $i < 24; $i++) {
$data[] = rand(50, 200);
}
return $data;
}
/**
* Speicher-Labels generieren
*/
private function getMemoryLabels()
{
return ['Min', 'Max', 'Durchschnitt', 'Aktuell'];
}
/**
* Speicher-Daten generieren
*/
private function getMemoryData()
{
$current = memory_get_usage() / (1024 * 1024);
return [
round($current * 0.8, 2),
round($current * 1.2, 2),
round($current, 2),
round($current, 2)
];
}
/**
* Datenbankverbindungen abrufen
*/
private function getDatabaseConnections()
{
try {
$connectionParams = [
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
'host' => getenv('DB_HOST') ?: 'db',
'driver' => 'pdo_mysql',
'port' => getenv('DB_PORT') ?: 3306,
'charset' => 'utf8mb4',
];
$conn = DriverManager::getConnection($connectionParams);
$stmt = $conn->prepare('SHOW STATUS LIKE "Threads_connected"');
$stmt->execute();
$result = $stmt->fetchAssociative();
return intval($result['Value'] ?? 0);
} catch (Exception $e) {
return 0;
}
}
/**
* Cache-Hit-Rate abrufen
*/
private function getCacheHitRate()
{
$stats = $this->cache->getStats();
$hits = $stats['hits'] ?? 0;
$misses = $stats['misses'] ?? 0;
$total = $hits + $misses;
return $total > 0 ? round($hits / $total * 100, 2) : 0;
}
/**
* Datenbank-Größe abrufen
*/
private function getDatabaseSize()
{
try {
$connectionParams = [
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
'host' => getenv('DB_HOST') ?: 'db',
'driver' => 'pdo_mysql',
'port' => getenv('DB_PORT') ?: 3306,
'charset' => 'utf8mb4',
];
$conn = DriverManager::getConnection($connectionParams);
$stmt = $conn->prepare('
SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = ?
');
$stmt->execute([getenv('DB_DATABASE') ?: 'freeshop']);
$result = $stmt->fetchAssociative();
return floatval($result['size_mb'] ?? 0);
} catch (Exception $e) {
return 0;
}
}
/**
* Aktive Sessions abrufen
*/
private function getActiveSessions()
{
$sessionDir = session_save_path() ?: '/tmp';
$sessions = glob($sessionDir . '/sess_*');
return count($sessions);
}
/**
* Durchschnittliche Ladezeit abrufen
*/
private function getAverageLoadTime()
{
// Simulierte Daten für Demo
return rand(100, 500);
}
/**
* Sitemap-Inhalt generieren
*/
private function generateSitemapContent()
{
$baseUrl = getenv('BASE_URL') ?: 'https://webshop.local';
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
// Startseite
$xml .= ' <url>' . "\n";
$xml .= ' <loc>' . $baseUrl . '</loc>' . "\n";
$xml .= ' <lastmod>' . date('Y-m-d') . '</lastmod>' . "\n";
$xml .= ' <changefreq>daily</changefreq>' . "\n";
$xml .= ' <priority>1.0</priority>' . "\n";
$xml .= ' </url>' . "\n";
// Produkte
try {
$connectionParams = [
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
'host' => getenv('DB_HOST') ?: 'db',
'driver' => 'pdo_mysql',
'port' => getenv('DB_PORT') ?: 3306,
'charset' => 'utf8mb4',
];
$conn = DriverManager::getConnection($connectionParams);
$stmt = $conn->prepare('SELECT id, updated_at FROM ws_product WHERE active = 1');
$stmt->execute();
$products = $stmt->fetchAllAssociative();
foreach ($products as $product) {
$xml .= ' <url>' . "\n";
$xml .= ' <loc>' . $baseUrl . '/product/' . $product['id'] . '</loc>' . "\n";
$xml .= ' <lastmod>' . date('Y-m-d', strtotime($product['updated_at'])) . '</lastmod>' . "\n";
$xml .= ' <changefreq>weekly</changefreq>' . "\n";
$xml .= ' <priority>0.8</priority>' . "\n";
$xml .= ' </url>' . "\n";
}
} catch (Exception $e) {
// Ignore database errors
}
$xml .= '</urlset>';
return $xml;
}
/**
* Bytes formatieren
*/
private function formatBytes($bytes, $precision = 2)
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
$bytes /= 1024;
}
return round($bytes, $precision) . ' ' . $units[$i];
}
/**
* Template rendern
*/
private function renderTemplate($template, $data = [])
{
extract($data);
include __DIR__ . '/../../templates/' . $template;
}
}