moduleManager = ModuleManager::getInstance(); $this->eventDispatcher = EventDispatcher::getInstance(); $this->cache = Cache::getInstance(); $this->logger = Logger::getInstance(); $this->loadApiKeys(); } /** * Singleton-Instanz abrufen */ public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * API-Request verarbeiten */ public function handleRequest($method, $endpoint, $data = [], $headers = []) { if (!$this->enabled) { return $this->createResponse(503, 'API deaktiviert'); } // API-Key validieren $apiKey = $this->extractApiKey($headers); if (!$this->validateApiKey($apiKey)) { return $this->createResponse(401, 'Ungültiger API-Key'); } // Rate-Limiting prüfen if (!$this->checkRateLimit($apiKey)) { return $this->createResponse(429, 'Rate-Limit überschritten'); } // Request loggen $this->logger->info('API Request', [ 'method' => $method, 'endpoint' => $endpoint, 'api_key' => $this->maskApiKey($apiKey), 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown' ]); try { // Endpoint auflösen $handler = $this->resolveEndpoint($method, $endpoint); if (!$handler) { return $this->createResponse(404, 'Endpoint nicht gefunden'); } // Request verarbeiten $result = call_user_func($handler, $data, $headers); // Response loggen $this->logger->info('API Response', [ 'method' => $method, 'endpoint' => $endpoint, 'status' => $result['status'] ?? 200 ]); return $result; } catch (\Exception $e) { $this->logger->error('API Error', [ 'method' => $method, 'endpoint' => $endpoint, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return $this->createResponse(500, 'Interner Server-Fehler: ' . $e->getMessage()); } } /** * Module-Liste abrufen */ public function getModules($filters = []) { $cacheKey = 'api_modules_' . md5(serialize($filters)); // Cache prüfen $cached = $this->cache->get($cacheKey); if ($cached !== null) { return $this->createResponse(200, 'Module abgerufen', $cached); } $modules = $this->moduleManager->getAllModules(); // Filter anwenden if (!empty($filters['active'])) { $modules = array_filter($modules, function($module) { return $module['active'] ?? false; }); } if (!empty($filters['type'])) { $modules = array_filter($modules, function($module) use ($filters) { return $module['type'] === $filters['type']; }); } if (!empty($filters['search'])) { $search = strtolower($filters['search']); $modules = array_filter($modules, function($module) use ($search) { return strpos(strtolower($module['name']), $search) !== false || strpos(strtolower($module['description']), $search) !== false; }); } // Pagination $page = $filters['page'] ?? 1; $limit = min($filters['limit'] ?? 20, 100); $offset = ($page - 1) * $limit; $total = count($modules); $modules = array_slice($modules, $offset, $limit); $result = [ 'modules' => $modules, 'pagination' => [ 'page' => $page, 'limit' => $limit, 'total' => $total, 'pages' => ceil($total / $limit) ] ]; // Cache setzen $this->cache->set($cacheKey, $result, 300); // 5 Minuten return $this->createResponse(200, 'Module abgerufen', $result); } /** * Einzelnes Modul abrufen */ public function getModule($moduleName) { $cacheKey = 'api_module_' . $moduleName; // Cache prüfen $cached = $this->cache->get($cacheKey); if ($cached !== null) { return $this->createResponse(200, 'Modul abgerufen', $cached); } $module = $this->moduleManager->getModule($moduleName); if (!$module) { return $this->createResponse(404, 'Modul nicht gefunden'); } // Cache setzen $this->cache->set($cacheKey, $module, 600); // 10 Minuten return $this->createResponse(200, 'Modul abgerufen', $module); } /** * Modul installieren */ public function installModule($moduleName, $data = []) { // Event auslösen $this->eventDispatcher->dispatch('module.install.before', [ 'module_name' => $moduleName, 'data' => $data ]); try { $result = $this->moduleManager->installModule($moduleName, $data); if ($result) { // Cache invalidieren $this->cache->delete('api_modules_*'); $this->cache->delete('api_module_' . $moduleName); // Event auslösen $this->eventDispatcher->dispatch('module.install.after', [ 'module_name' => $moduleName, 'result' => $result ]); $this->logger->info('Module installiert via API', [ 'module_name' => $moduleName, 'data' => $data ]); return $this->createResponse(201, 'Modul erfolgreich installiert', $result); } else { return $this->createResponse(400, 'Modul-Installation fehlgeschlagen'); } } catch (\Exception $e) { $this->logger->error('Module-Installation Fehler', [ 'module_name' => $moduleName, 'error' => $e->getMessage() ]); return $this->createResponse(500, 'Installation-Fehler: ' . $e->getMessage()); } } /** * Modul deinstallieren */ public function uninstallModule($moduleName) { // Event auslösen $this->eventDispatcher->dispatch('module.uninstall.before', [ 'module_name' => $moduleName ]); try { $result = $this->moduleManager->uninstallModule($moduleName); if ($result) { // Cache invalidieren $this->cache->delete('api_modules_*'); $this->cache->delete('api_module_' . $moduleName); // Event auslösen $this->eventDispatcher->dispatch('module.uninstall.after', [ 'module_name' => $moduleName, 'result' => $result ]); $this->logger->info('Module deinstalliert via API', [ 'module_name' => $moduleName ]); return $this->createResponse(200, 'Modul erfolgreich deinstalliert'); } else { return $this->createResponse(400, 'Modul-Deinstallation fehlgeschlagen'); } } catch (\Exception $e) { $this->logger->error('Module-Deinstallation Fehler', [ 'module_name' => $moduleName, 'error' => $e->getMessage() ]); return $this->createResponse(500, 'Deinstallation-Fehler: ' . $e->getMessage()); } } /** * Modul aktivieren */ public function enableModule($moduleName) { try { $result = $this->moduleManager->enableModule($moduleName); if ($result) { // Cache invalidieren $this->cache->delete('api_modules_*'); $this->cache->delete('api_module_' . $moduleName); $this->logger->info('Module aktiviert via API', [ 'module_name' => $moduleName ]); return $this->createResponse(200, 'Modul erfolgreich aktiviert'); } else { return $this->createResponse(400, 'Modul-Aktivierung fehlgeschlagen'); } } catch (\Exception $e) { $this->logger->error('Module-Aktivierung Fehler', [ 'module_name' => $moduleName, 'error' => $e->getMessage() ]); return $this->createResponse(500, 'Aktivierungs-Fehler: ' . $e->getMessage()); } } /** * Modul deaktivieren */ public function disableModule($moduleName) { try { $result = $this->moduleManager->disableModule($moduleName); if ($result) { // Cache invalidieren $this->cache->delete('api_modules_*'); $this->cache->delete('api_module_' . $moduleName); $this->logger->info('Module deaktiviert via API', [ 'module_name' => $moduleName ]); return $this->createResponse(200, 'Modul erfolgreich deaktiviert'); } else { return $this->createResponse(400, 'Modul-Deaktivierung fehlgeschlagen'); } } catch (\Exception $e) { $this->logger->error('Module-Deaktivierung Fehler', [ 'module_name' => $moduleName, 'error' => $e->getMessage() ]); return $this->createResponse(500, 'Deaktivierungs-Fehler: ' . $e->getMessage()); } } /** * Modul-Konfiguration abrufen */ public function getModuleConfig($moduleName) { $cacheKey = 'api_module_config_' . $moduleName; // Cache prüfen $cached = $this->cache->get($cacheKey); if ($cached !== null) { return $this->createResponse(200, 'Modul-Konfiguration abgerufen', $cached); } $config = $this->moduleManager->getModuleConfig($moduleName); if (!$config) { return $this->createResponse(404, 'Modul-Konfiguration nicht gefunden'); } // Cache setzen $this->cache->set($cacheKey, $config, 300); // 5 Minuten return $this->createResponse(200, 'Modul-Konfiguration abgerufen', $config); } /** * Modul-Konfiguration aktualisieren */ public function updateModuleConfig($moduleName, $config) { try { $result = $this->moduleManager->updateModuleConfig($moduleName, $config); if ($result) { // Cache invalidieren $this->cache->delete('api_module_config_' . $moduleName); $this->logger->info('Module-Konfiguration aktualisiert via API', [ 'module_name' => $moduleName, 'config' => $config ]); return $this->createResponse(200, 'Modul-Konfiguration erfolgreich aktualisiert'); } else { return $this->createResponse(400, 'Konfigurations-Update fehlgeschlagen'); } } catch (\Exception $e) { $this->logger->error('Module-Konfigurations-Update Fehler', [ 'module_name' => $moduleName, 'error' => $e->getMessage() ]); return $this->createResponse(500, 'Update-Fehler: ' . $e->getMessage()); } } /** * Module-Statistiken abrufen */ public function getModuleStatistics() { $cacheKey = 'api_module_statistics'; // Cache prüfen $cached = $this->cache->get($cacheKey); if ($cached !== null) { return $this->createResponse(200, 'Module-Statistiken abgerufen', $cached); } $statistics = $this->moduleManager->getStatistics(); // Cache setzen $this->cache->set($cacheKey, $statistics, 600); // 10 Minuten return $this->createResponse(200, 'Module-Statistiken abgerufen', $statistics); } /** * API-Status abrufen */ public function getApiStatus() { $status = [ 'enabled' => $this->enabled, 'version' => '1.0.0', 'rate_limit' => $this->rateLimit, 'rate_limit_window' => $this->rateLimitWindow, 'total_modules' => count($this->moduleManager->getAllModules()), 'active_modules' => count(array_filter($this->moduleManager->getAllModules(), function($m) { return $m['active'] ?? false; })), 'uptime' => time() - strtotime('today'), 'memory_usage' => memory_get_usage(true), 'memory_peak' => memory_get_peak_usage(true) ]; return $this->createResponse(200, 'API-Status abgerufen', $status); } /** * Endpoint auflösen */ private function resolveEndpoint($method, $endpoint) { $endpoints = [ 'GET' => [ '/api/v1/modules' => [$this, 'getModules'], '/api/v1/modules/{name}' => [$this, 'getModule'], '/api/v1/modules/{name}/config' => [$this, 'getModuleConfig'], '/api/v1/statistics' => [$this, 'getModuleStatistics'], '/api/v1/status' => [$this, 'getApiStatus'] ], 'POST' => [ '/api/v1/modules' => [$this, 'installModule'], '/api/v1/modules/{name}/enable' => [$this, 'enableModule'], '/api/v1/modules/{name}/disable' => [$this, 'disableModule'], '/api/v1/modules/{name}/config' => [$this, 'updateModuleConfig'] ], 'DELETE' => [ '/api/v1/modules/{name}' => [$this, 'uninstallModule'] ] ]; if (!isset($endpoints[$method])) { return null; } foreach ($endpoints[$method] as $pattern => $handler) { if ($this->matchPattern($pattern, $endpoint)) { return $handler; } } return null; } /** * Pattern-Matching für Endpoints */ private function matchPattern($pattern, $endpoint) { $pattern = preg_replace('/\{([^}]+)\}/', '([^/]+)', $pattern); return preg_match('#^' . $pattern . '$#', $endpoint); } /** * API-Key aus Headers extrahieren */ private function extractApiKey($headers) { $apiKey = null; // Verschiedene Header-Namen prüfen $headerNames = ['X-API-Key', 'Authorization', 'Api-Key']; foreach ($headerNames as $headerName) { if (isset($headers[$headerName])) { $value = $headers[$headerName]; // Bearer Token Format if (strpos($value, 'Bearer ') === 0) { $apiKey = substr($value, 7); } else { $apiKey = $value; } break; } } return $apiKey; } /** * API-Key validieren */ private function validateApiKey($apiKey) { if (!$apiKey) { return false; } return isset($this->apiKeys[$apiKey]) && $this->apiKeys[$apiKey]['active']; } /** * Rate-Limiting prüfen */ private function checkRateLimit($apiKey) { $cacheKey = 'api_rate_limit_' . md5($apiKey); $current = time(); $requests = $this->cache->get($cacheKey, []); // Alte Requests entfernen $requests = array_filter($requests, function($timestamp) use ($current) { return $timestamp > ($current - $this->rateLimitWindow); }); // Neuen Request hinzufügen $requests[] = $current; // Cache aktualisieren $this->cache->set($cacheKey, $requests, $this->rateLimitWindow); return count($requests) <= $this->rateLimit; } /** * API-Keys laden */ private function loadApiKeys() { try { $conn = DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $stmt = $conn->prepare(' SELECT api_key, name, permissions, active, created_at FROM ws_api_keys WHERE active = 1 '); $stmt->execute(); $keys = $stmt->fetchAllAssociative(); foreach ($keys as $key) { $this->apiKeys[$key['api_key']] = [ 'name' => $key['name'], 'permissions' => json_decode($key['permissions'], true) ?: [], 'active' => (bool)$key['active'], 'created_at' => $key['created_at'] ]; } } catch (Exception $e) { $this->logger->error('API-Keys laden Fehler', [ 'error' => $e->getMessage() ]); } } /** * API-Key maskieren für Logs */ private function maskApiKey($apiKey) { if (strlen($apiKey) <= 8) { return str_repeat('*', strlen($apiKey)); } return substr($apiKey, 0, 4) . str_repeat('*', strlen($apiKey) - 8) . substr($apiKey, -4); } /** * Response erstellen */ private function createResponse($status, $message, $data = null) { $response = [ 'status' => $status, 'message' => $message, 'timestamp' => date('c'), 'request_id' => uniqid('api_', true) ]; if ($data !== null) { $response['data'] = $data; } return $response; } /** * API aktivieren/deaktivieren */ public function setEnabled($enabled) { $this->enabled = $enabled; return $this; } /** * API-Status prüfen */ public function isEnabled() { return $this->enabled; } /** * Rate-Limit setzen */ public function setRateLimit($limit, $window = 3600) { $this->rateLimit = $limit; $this->rateLimitWindow = $window; return $this; } /** * API-Key erstellen */ public function createApiKey($name, $permissions = []) { try { $conn = DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $apiKey = $this->generateApiKey(); $stmt = $conn->prepare(' INSERT INTO ws_api_keys ( api_key, name, permissions, active, created_at ) VALUES (?, ?, ?, 1, NOW()) '); $stmt->execute([ $apiKey, $name, json_encode($permissions) ]); // API-Keys neu laden $this->loadApiKeys(); $this->logger->info('API-Key erstellt', [ 'name' => $name, 'permissions' => $permissions ]); return $apiKey; } catch (Exception $e) { $this->logger->error('API-Key erstellen Fehler', [ 'error' => $e->getMessage() ]); return false; } } /** * API-Key löschen */ public function deleteApiKey($apiKey) { try { $conn = DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $stmt = $conn->prepare(' DELETE FROM ws_api_keys WHERE api_key = ? '); $stmt->execute([$apiKey]); // API-Keys neu laden $this->loadApiKeys(); $this->logger->info('API-Key gelöscht', [ 'api_key' => $this->maskApiKey($apiKey) ]); return true; } catch (Exception $e) { $this->logger->error('API-Key löschen Fehler', [ 'error' => $e->getMessage() ]); return false; } } /** * API-Key generieren */ private function generateApiKey() { return 'ws_' . bin2hex(random_bytes(32)); } }