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 = '' . "\n"; $xml .= '' . "\n"; // Startseite $xml .= ' ' . "\n"; $xml .= ' ' . $baseUrl . '' . "\n"; $xml .= ' ' . date('Y-m-d') . '' . "\n"; $xml .= ' daily' . "\n"; $xml .= ' 1.0' . "\n"; $xml .= ' ' . "\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 .= ' ' . "\n"; $xml .= ' ' . $baseUrl . '/product/' . $product['id'] . '' . "\n"; $xml .= ' ' . date('Y-m-d', strtotime($product['updated_at'])) . '' . "\n"; $xml .= ' weekly' . "\n"; $xml .= ' 0.8' . "\n"; $xml .= ' ' . "\n"; } } catch (Exception $e) { // Ignore database errors } $xml .= ''; 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; } }