Newwebshop/app/controllers/admin/ModuleController.php

431 lines
12 KiB
PHP

<?php
/**
* Copyright seit 2024 Webshop System
*
* Module Controller für Admin-Bereich
*
* @author Webshop System
* @license GPL v3
*/
namespace App\Controllers\Admin;
use App\Core\Module;
use App\Core\Hook;
use App\Core\MultiShop;
use App\Core\Security;
use App\Core\Configuration;
class ModuleController
{
private $multiShop;
private $security;
private $config;
public function __construct()
{
$this->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;
}
}