"Update-Ziel ist nicht konfiguriert.", "available" => false, "version" => "", ]; } $context = stream_context_create([ "http" => [ "method" => "GET", "timeout" => 3, "ignore_errors" => true, "header" => "User-Agent: PSA-Orderform-Settings/" . APP_VERSION . "\r\n", ], ]); $body = @file_get_contents($manifestUrl, false, $context); if ($body === false) { return [ "label" => "Update-Status konnte nicht geladen werden.", "available" => false, "version" => "", ]; } $manifest = json_decode($body, true); if (!is_array($manifest)) { return [ "label" => "Update-Status ist ungültig.", "available" => false, "version" => "", ]; } $version = trim((string) ($manifest["version"] ?? $manifest["latest"] ?? "")); if (!preg_match('/^v\d+\.\d+\.\d+$/', $version)) { return [ "label" => "Update-Version ist ungültig.", "available" => false, "version" => "", ]; } $available = version_compare( settingsUpdaterVersionCompareValue($version), settingsUpdaterVersionCompareValue(APP_VERSION), ">", ); return [ "label" => $available ? "Update verfügbar: " . $version : "Kein Update verfügbar.", "available" => $available, "version" => $version, ]; } function settingsFormatBackupDate(string $date): string { $timestamp = strtotime($date); if ($timestamp === false) { return $date; } return date("d.m.Y H:i", $timestamp); } function settingsGetBackupUploadLabel(array $backup): string { $uploads = isset($backup["remote_uploads"]) && is_array($backup["remote_uploads"]) ? $backup["remote_uploads"] : []; if (empty($uploads)) { return "Nur lokal"; } $successful = 0; foreach ($uploads as $upload) { if (is_array($upload) && !empty($upload["success"])) { $successful++; } } if ($successful === count($uploads)) { return "Remote erfolgreich (" . $successful . ")"; } if ($successful > 0) { return "Teilweise erfolgreich (" . $successful . "/" . count($uploads) . ")"; } return "Remote fehlgeschlagen"; } function settingsGetBackupCapabilityLabel(array $capability): string { if (empty($capability["configured"])) { return "nicht konfiguriert"; } return !empty($capability["available"]) ? "bereit" : "nicht verfügbar"; } function settingsIsSuperAdmin(): bool { return normalizeAdminUsername($_SESSION['admin_username'] ?? "") === "admin"; } function settingsGetLocalConfigPath(): string { return dirname(__DIR__) . "/config.php"; } function settingsReadLocalConfig(): string { $path = settingsGetLocalConfigPath(); if (!is_file($path) || !is_readable($path)) { return ""; } $content = file_get_contents($path); return $content === false ? "" : $content; } function settingsWriteLocalConfig(string $content): void { $content = str_replace("\r\n", "\n", $content); if (!str_starts_with(ltrim($content), "getMessage()); } $path = settingsGetLocalConfigPath(); $tmpFile = $path . ".tmp"; if (file_put_contents($tmpFile, $content, LOCK_EX) === false) { throw new RuntimeException("Konfiguration konnte nicht geschrieben werden."); } $backupDir = DATA_DIR . "backups/config/"; if (!is_dir($backupDir) && !mkdir($backupDir, 0775, true) && !is_dir($backupDir)) { @unlink($tmpFile); throw new RuntimeException("Sicherungsverzeichnis konnte nicht angelegt werden."); } if (is_file($path)) { $backupPath = $backupDir . "config-" . date("Ymd-His") . ".php.bak"; if (!copy($path, $backupPath)) { @unlink($tmpFile); throw new RuntimeException("Sicherung der bestehenden Konfiguration ist fehlgeschlagen."); } } @chmod($tmpFile, 0664); if (!rename($tmpFile, $path)) { @unlink($tmpFile); throw new RuntimeException("Konfiguration konnte nicht gespeichert werden."); } if (function_exists("opcache_invalidate")) { opcache_invalidate($path, true); } } function settingsFindBackupByFilename(string $filename): ?array { if ($filename === "" || basename($filename) !== $filename) { return null; } foreach (backupListBackups() as $backup) { if (($backup["filename"] ?? "") === $filename) { return $backup; } } return null; } function settingsSendBackupDownload(array $backup): void { $filename = basename((string) ($backup["filename"] ?? "")); $path = backupGetDirectory() . $filename; if ($filename === "" || !is_file($path) || !is_readable($path)) { throw new RuntimeException("Backup-Datei wurde nicht gefunden."); } $size = filesize($path); if ($size === false) { throw new RuntimeException("Backup-Dateigröße konnte nicht gelesen werden."); } logAccess("Backup downloaded", [ "filename" => $filename, ]); header("Content-Type: application/zip"); header('Content-Disposition: attachment; filename="' . $filename . '"'); header("Content-Length: " . (string) $size); header("X-Content-Type-Options: nosniff"); readfile($path); exit(); } if (empty($_SESSION['admin_logged_in'])) { header("Location: login.php"); exit(); } $pageTitle = "Einstellungen"; $message = ""; $messageType = ""; $isSuperAdmin = settingsIsSuperAdmin(); if ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_settings'])) { // Validate CSRF token if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $settings = array_merge(getSystemSettings(), [ "order_recipient_email" => $_POST['order_recipient_email'] ?? "", "attach_order_pdf_to_admin_email" => isset( $_POST['attach_order_pdf_to_admin_email'], ), "nametag_product_name" => $_POST['nametag_product_name'] ?? "", ]); if (saveSystemSettings($settings)) { logAccess("Admin updated system settings"); $message = "Einstellungen wurden gespeichert."; $messageType = "success"; } else { $message = "Einstellungen konnten nicht gespeichert werden."; $messageType = "error"; } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['create_backup'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { try { $backup = backupCreate("manual"); $message = "Backup wurde erstellt: " . $backup["filename"] . " (" . backupFormatBytes((int) $backup["size"]) . ")."; $messageType = "success"; } catch (Throwable $exception) { $message = "Backup konnte nicht erstellt werden: " . $exception->getMessage(); $messageType = "error"; } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['download_backup'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { try { $backup = settingsFindBackupByFilename((string) ($_POST["backup_filename"] ?? "")); if ($backup === null) { throw new RuntimeException("Backup wurde nicht gefunden."); } settingsSendBackupDownload($backup); } catch (Throwable $exception) { $message = "Backup konnte nicht heruntergeladen werden: " . $exception->getMessage(); $messageType = "error"; } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_local_config'])) { if (!$isSuperAdmin) { http_response_code(403); $message = "Keine Berechtigung für diese Aktion."; $messageType = "error"; } elseif (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { try { settingsWriteLocalConfig((string) ($_POST['local_config_content'] ?? "")); logAccess("Admin updated local config.php"); $message = "Lokale Konfiguration wurde gespeichert."; $messageType = "success"; } catch (Throwable $exception) { $message = "Konfiguration konnte nicht gespeichert werden: " . $exception->getMessage(); $messageType = "error"; } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['add_category'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $categories = getCategories(); $label = normalizeCategoryLabel($_POST['category_label'] ?? ""); if (!isValidCategoryLabel($label)) { $message = "Bitte geben Sie einen Kategorienamen mit maximal 80 Zeichen ein."; $messageType = "error"; } else { $categoryId = generateCategoryIdFromLabel($label, $categories); $categories[] = [ "id" => $categoryId, "label" => $label, ]; if (saveCategories($categories)) { logAccess("Admin added category", [ "category_id" => $categoryId, "label" => $label, ]); $message = "Kategorie wurde erfolgreich angelegt."; $messageType = "success"; } else { $message = "Kategorie konnte nicht gespeichert werden."; $messageType = "error"; } } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['update_category'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $categories = getCategories(); $categoryId = normalizeCategoryId($_POST['category_id'] ?? ""); $label = normalizeCategoryLabel($_POST['category_label'] ?? ""); $found = false; if (!isValidCategoryLabel($label)) { $message = "Bitte geben Sie einen Kategorienamen mit maximal 80 Zeichen ein."; $messageType = "error"; } else { foreach ($categories as &$category) { if ($category["id"] === $categoryId) { $category["label"] = $label; $found = true; break; } } unset($category); if (!$found) { $message = "Kategorie nicht gefunden."; $messageType = "error"; } elseif (saveCategories($categories)) { logAccess("Admin updated category", [ "category_id" => $categoryId, "label" => $label, ]); $message = "Kategorie wurde erfolgreich aktualisiert."; $messageType = "success"; } else { $message = "Kategorie konnte nicht gespeichert werden."; $messageType = "error"; } } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['delete_category'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $categoryId = normalizeCategoryId($_POST['category_id'] ?? ""); $label = ""; $found = false; if (isCategoryInUse($categoryId)) { $message = "Diese Kategorie wird noch von Produkten verwendet und kann nicht gelöscht werden."; $messageType = "error"; } else { $categories = array_values( array_filter(getCategories(), function ($category) use ( $categoryId, &$found, &$label, ) { if ($category["id"] === $categoryId) { $found = true; $label = $category["label"]; return false; } return true; }), ); if (!$found) { $message = "Kategorie nicht gefunden."; $messageType = "error"; } elseif (saveCategories($categories)) { logAccess("Admin deleted category", [ "category_id" => $categoryId, "label" => $label, ]); $message = "Kategorie wurde gelöscht."; $messageType = "success"; } else { $message = "Kategorie konnte nicht gelöscht werden."; $messageType = "error"; } } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_faq'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $content = isset($_POST['content']) ? (string) $_POST['content'] : ""; $faqSettings = array_merge(getSystemSettings(), [ "startpage_intro_text" => isset($_POST['startpage_intro_text']) ? (string) $_POST['startpage_intro_text'] : "", ]); if (saveFaqContent($content) && saveSystemSettings($faqSettings)) { logAccess("Admin updated FAQ content"); $message = "FAQ-Inhalt und Startseitentext wurden gespeichert."; $messageType = "success"; } else { $message = "FAQ-Inhalt und/oder Startseitentext konnten nicht gespeichert werden."; $messageType = "error"; } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['add_organization'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $organizations = getOrganizations(false); $label = normalizeOrganizationLabel($_POST['organization_label'] ?? ""); $sortOrder = (int) ($_POST['sort_order'] ?? 0); $active = isset($_POST['active']); if (!isValidOrganizationLabel($label)) { $message = "Bitte einen Organisationsnamen mit maximal 120 Zeichen eingeben."; $messageType = "error"; } else { $orgId = generateOrganizationIdFromLabel($label, $organizations); $organizations[] = [ "id" => $orgId, "label" => $label, "sort_order" => $sortOrder, "active" => $active, ]; if (saveOrganizations($organizations)) { logAccess("Admin added organization", [ "org_id" => $orgId, "label" => $label, ]); $message = "Organisation wurde angelegt."; $messageType = "success"; } else { $message = "Organisation konnte nicht gespeichert werden."; $messageType = "error"; } } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['update_organization'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $organizations = getOrganizations(false); $organizationId = normalizeOrganizationId($_POST['organization_id'] ?? ""); $label = normalizeOrganizationLabel($_POST['organization_label'] ?? ""); $sortOrder = (int) ($_POST['sort_order'] ?? 0); $active = isset($_POST['active']); $updated = false; if (!isValidOrganizationLabel($label)) { $message = "Bitte einen Organisationsnamen mit maximal 120 Zeichen eingeben."; $messageType = "error"; } else { foreach ($organizations as &$organization) { if ($organization["id"] !== $organizationId) { continue; } $organization["label"] = $label; $organization["sort_order"] = $sortOrder; $organization["active"] = $active; $updated = true; break; } unset($organization); if (!$updated) { $message = "Organisation nicht gefunden."; $messageType = "error"; } elseif (saveOrganizations($organizations)) { logAccess("Admin updated organization", [ "org_id" => $organizationId, "label" => $label, ]); $message = "Organisation wurde aktualisiert."; $messageType = "success"; } else { $message = "Organisation konnte nicht gespeichert werden."; $messageType = "error"; } } } } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['delete_organization'])) { if (!validateCsrfToken($_POST['csrf_token'] ?? "")) { $message = "Ungültiges Token. Bitte versuchen Sie es erneut."; $messageType = "error"; } else { $organizationId = normalizeOrganizationId($_POST['organization_id'] ?? ""); $orgLabel = ""; foreach (getOrganizations(false) as $organization) { if ($organization["id"] === $organizationId) { $orgLabel = $organization["label"]; break; } } $organizations = array_values( array_filter(getOrganizations(false), function ($organization) use ( $organizationId, ) { return $organization["id"] !== $organizationId; }), ); if (saveOrganizations($organizations)) { logAccess("Admin deleted organization", [ "org_id" => $organizationId, "label" => $orgLabel, ]); $message = "Organisation wurde gelöscht."; $messageType = "success"; } else { $message = "Organisation konnte nicht gelöscht werden."; $messageType = "error"; } } } $settings = getSystemSettings(); $updaterStatus = settingsGetUpdaterStatus(); $backupCapabilities = backupRemoteCapabilities(); $backups = backupListBackups(); $localConfigContent = $isSuperAdmin ? settingsReadLocalConfig() : ""; $categories = getCategories(); $products = getProducts(); $organizations = getOrganizations(false); $faqContent = getFaqContent(); $startpageIntroText = (string) ($settings["startpage_intro_text"] ?? ""); $editCategoryId = normalizeCategoryId($_GET['edit_category'] ?? ""); $editingCategory = null; if ($editCategoryId !== "") { $editingCategory = getCategoryById($editCategoryId); if ($editingCategory === null && $message === "") { $message = "Ausgewählte Kategorie wurde nicht gefunden."; $messageType = "error"; } } $editingOrganization = isset($_GET['edit_organization']) ? getOrganizationById($_GET['edit_organization']) : null; $bodyClass = "admin-page"; include __DIR__ . "/../includes/header.php"; ?>
| Name | ID | Produkte | Aktionen |
|---|---|---|---|
|
#kategorien" class="btn btn-small btn-secondary">Bearbeiten |
Unterstützte Markdown-Syntax: #, ##, ###, **fett**, *kursiv*, Listen mit - oder 1., Links mit [Text](https://example.com)
| Name | ID | Sortierung | Status | Aktionen |
|---|---|---|---|---|
|
"> | #organisationen" class="btn btn-small">Bearbeiten |
Lokale Aufbewahrung: Backups
Automatisches Intervall: Tage
S3: · SFTP: · Custom: · Managed:
Es wurden noch keine Backups erstellt.
| Erstellt | Auslöser | Größe | Dateien | Remote | Aktionen |
|---|---|---|---|---|---|
Bearbeitet config.php direkt auf diesem Server. Diese Datei wird beim Update nicht überschrieben.