431 lines
12 KiB
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;
|
|
}
|
|
}
|