multiShop = new MultiShop(); $this->security = new Security(); $this->config = new Configuration(); // Session-Check if (!isset($_SESSION['admin_logged_in']) || !$_SESSION['admin_logged_in']) { header('Location: /admin/login'); exit; } } /** * Modul-Übersicht anzeigen */ public function index() { $shopId = $this->multiShop->getCurrentShopId(); // Module aus Datenbank abrufen $modules = $this->getModules(); // Hook-Statistiken $hookStats = Hook::getHookStatistics(); $data = [ 'modules' => $modules, 'hook_stats' => $hookStats, 'shop_id' => $shopId ]; $this->render('admin/module/index.html.twig', $data); } /** * Modul installieren */ public function install() { $moduleName = $_POST['module_name'] ?? ''; if (empty($moduleName)) { $this->addError('Modul-Name ist erforderlich'); header('Location: /admin/module'); return; } // CSRF-Schutz if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) { $this->addError('Sicherheitsfehler: Ungültiger Token'); header('Location: /admin/module'); return; } try { $module = $this->loadModule($moduleName); if (!$module) { $this->addError("Modul '{$moduleName}' nicht gefunden"); header('Location: /admin/module'); return; } if ($module->install()) { $this->addSuccess("Modul '{$moduleName}' erfolgreich installiert"); } else { $this->addError("Fehler beim Installieren von '{$moduleName}'"); } } catch (\Exception $e) { $this->addError('Installationsfehler: ' . $e->getMessage()); } header('Location: /admin/module'); } /** * Modul deinstallieren */ public function uninstall() { $moduleName = $_POST['module_name'] ?? ''; if (empty($moduleName)) { $this->addError('Modul-Name ist erforderlich'); header('Location: /admin/module'); return; } // CSRF-Schutz if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) { $this->addError('Sicherheitsfehler: Ungültiger Token'); header('Location: /admin/module'); return; } try { $module = $this->loadModule($moduleName); if (!$module) { $this->addError("Modul '{$moduleName}' nicht gefunden"); header('Location: /admin/module'); return; } if ($module->uninstall()) { $this->addSuccess("Modul '{$moduleName}' erfolgreich deinstalliert"); } else { $this->addError("Fehler beim Deinstallieren von '{$moduleName}'"); } } catch (\Exception $e) { $this->addError('Deinstallationsfehler: ' . $e->getMessage()); } header('Location: /admin/module'); } /** * Modul konfigurieren */ public function configure() { $moduleName = $_GET['module'] ?? ''; if (empty($moduleName)) { $this->addError('Modul-Name ist erforderlich'); header('Location: /admin/module'); return; } $module = $this->loadModule($moduleName); if (!$module) { $this->addError("Modul '{$moduleName}' nicht gefunden"); header('Location: /admin/module'); return; } // POST-Verarbeitung if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->processModuleConfiguration($module); } $data = [ 'module' => $module, 'module_info' => $module->getModuleInfo(), 'configuration' => $this->getModuleConfiguration($moduleName) ]; $this->render('admin/module/configure.html.twig', $data); } /** * Modul-Konfiguration verarbeiten */ private function processModuleConfiguration($module) { // CSRF-Schutz if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) { $this->addError('Sicherheitsfehler: Ungültiger Token'); return; } $moduleName = $module->name; // Konfiguration verarbeiten foreach ($_POST as $key => $value) { if (strpos($key, 'config_') === 0) { $configKey = substr($key, 7); // 'config_' entfernen $module->setConfig($configKey, $value); } } $this->addSuccess('Modul-Konfiguration erfolgreich gespeichert'); } /** * Module aus Datenbank abrufen */ private function getModules() { try { $conn = \Doctrine\DBAL\DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $stmt = $conn->prepare(' SELECT * FROM ws_module ORDER BY display_name ASC '); $stmt->execute(); return $stmt->fetchAllAssociative(); } catch (\Exception $e) { error_log('Module-Abruf Fehler: ' . $e->getMessage()); return []; } } /** * Modul laden */ private function loadModule($moduleName) { $modulePath = __DIR__ . '/../../modules/' . $moduleName . '/' . $moduleName . '.php'; if (!file_exists($modulePath)) { return null; } require_once $modulePath; $className = ucfirst($moduleName); if (class_exists($className)) { return new $className(); } return null; } /** * Modul-Konfiguration abrufen */ private function getModuleConfiguration($moduleName) { try { $conn = \Doctrine\DBAL\DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $stmt = $conn->prepare(' SELECT config_key, config_value FROM ws_module_config WHERE module_name = ? '); $stmt->execute([$moduleName]); $config = []; while ($row = $stmt->fetchAssociative()) { $config[$row['config_key']] = $row['config_value']; } return $config; } catch (\Exception $e) { error_log('Modul-Konfiguration Fehler: ' . $e->getMessage()); return []; } } /** * Modul-Logs abrufen */ public function logs() { $moduleName = $_GET['module'] ?? ''; try { $conn = \Doctrine\DBAL\DriverManager::getConnection([ 'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop' ]); $sql = 'SELECT * FROM ws_module_log'; $params = []; if (!empty($moduleName)) { $sql .= ' WHERE module_name = ?'; $params[] = $moduleName; } $sql .= ' ORDER BY created_at DESC LIMIT 100'; $stmt = $conn->prepare($sql); $stmt->execute($params); $logs = $stmt->fetchAllAssociative(); $data = [ 'logs' => $logs, 'module_name' => $moduleName ]; $this->render('admin/module/logs.html.twig', $data); } catch (\Exception $e) { $this->addError('Log-Abruf Fehler: ' . $e->getMessage()); $this->render('admin/module/logs.html.twig', ['logs' => [], 'module_name' => $moduleName]); } } /** * Hook-Übersicht anzeigen */ public function hooks() { $hookList = Hook::getHookList(); $hookStats = Hook::getHookStatistics(); $data = [ 'hook_list' => $hookList, 'hook_stats' => $hookStats ]; $this->render('admin/module/hooks.html.twig', $data); } /** * Modul-Upload verarbeiten */ public function upload() { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { header('Location: /admin/module'); return; } // CSRF-Schutz if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) { $this->addError('Sicherheitsfehler: Ungültiger Token'); header('Location: /admin/module'); return; } if (!isset($_FILES['module_file']) || $_FILES['module_file']['error'] !== UPLOAD_ERR_OK) { $this->addError('Fehler beim Datei-Upload'); header('Location: /admin/module'); return; } $uploadDir = __DIR__ . '/../../modules/'; $fileName = $_FILES['module_file']['name']; $filePath = $_FILES['module_file']['tmp_name']; // ZIP-Datei extrahieren $zip = new \ZipArchive(); if ($zip->open($filePath) === TRUE) { $moduleName = pathinfo($fileName, PATHINFO_FILENAME); $extractPath = $uploadDir . $moduleName . '/'; // Verzeichnis erstellen if (!is_dir($extractPath)) { mkdir($extractPath, 0755, true); } // Dateien extrahieren $zip->extractTo($extractPath); $zip->close(); $this->addSuccess("Modul '{$moduleName}' erfolgreich hochgeladen"); } else { $this->addError('Fehler beim Extrahieren der ZIP-Datei'); } header('Location: /admin/module'); } /** * Template rendern */ private function render($template, $data = []) { // CSRF-Token generieren $data['csrf_token'] = $this->security->generateCSRFToken(); // Flash-Messages $data['success_messages'] = $_SESSION['success_messages'] ?? []; $data['error_messages'] = $_SESSION['error_messages'] ?? []; // Session-Messages löschen unset($_SESSION['success_messages'], $_SESSION['error_messages']); // Template laden $templatePath = __DIR__ . '/../../templates/' . $template; if (file_exists($templatePath)) { extract($data); include $templatePath; } else { throw new \Exception("Template nicht gefunden: {$template}"); } } /** * Erfolgs-Message hinzufügen */ private function addSuccess($message) { if (!isset($_SESSION['success_messages'])) { $_SESSION['success_messages'] = []; } $_SESSION['success_messages'][] = $message; } /** * Fehler-Message hinzufügen */ private function addError($message) { if (!isset($_SESSION['error_messages'])) { $_SESSION['error_messages'] = []; } $_SESSION['error_messages'][] = $message; } }