settings.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <?php
  2. require_once __DIR__ . "/../config.php";
  3. require_once __DIR__ . "/../includes/functions.php";
  4. require_once __DIR__ . "/../includes/version.php";
  5. require_once __DIR__ . "/../includes/backup.php";
  6. if (!defined("UPDATE_MANIFEST_URL")) {
  7. define("UPDATE_MANIFEST_URL", "");
  8. }
  9. function settingsUpdaterVersionCompareValue(string $version): string
  10. {
  11. return ltrim(trim($version), "vV");
  12. }
  13. function settingsGetUpdaterStatus(): array
  14. {
  15. $manifestUrl = trim((string) UPDATE_MANIFEST_URL);
  16. if ($manifestUrl === "") {
  17. return [
  18. "label" => "Update-Ziel ist nicht konfiguriert.",
  19. "available" => false,
  20. "version" => "",
  21. ];
  22. }
  23. $context = stream_context_create([
  24. "http" => [
  25. "method" => "GET",
  26. "timeout" => 3,
  27. "ignore_errors" => true,
  28. "header" => "User-Agent: PSA-Orderform-Settings/" . APP_VERSION . "\r\n",
  29. ],
  30. ]);
  31. $body = @file_get_contents($manifestUrl, false, $context);
  32. if ($body === false) {
  33. return [
  34. "label" => "Update-Status konnte nicht geladen werden.",
  35. "available" => false,
  36. "version" => "",
  37. ];
  38. }
  39. $manifest = json_decode($body, true);
  40. if (!is_array($manifest)) {
  41. return [
  42. "label" => "Update-Status ist ungültig.",
  43. "available" => false,
  44. "version" => "",
  45. ];
  46. }
  47. $version = trim((string) ($manifest["version"] ?? $manifest["latest"] ?? ""));
  48. if (!preg_match('/^v\d+\.\d+\.\d+$/', $version)) {
  49. return [
  50. "label" => "Update-Version ist ungültig.",
  51. "available" => false,
  52. "version" => "",
  53. ];
  54. }
  55. $available =
  56. version_compare(
  57. settingsUpdaterVersionCompareValue($version),
  58. settingsUpdaterVersionCompareValue(APP_VERSION),
  59. ">",
  60. );
  61. return [
  62. "label" => $available
  63. ? "Update verfügbar: " . $version
  64. : "Kein Update verfügbar.",
  65. "available" => $available,
  66. "version" => $version,
  67. ];
  68. }
  69. function settingsFormatBackupDate(string $date): string
  70. {
  71. $timestamp = strtotime($date);
  72. if ($timestamp === false) {
  73. return $date;
  74. }
  75. return date("d.m.Y H:i", $timestamp);
  76. }
  77. function settingsGetBackupUploadLabel(array $backup): string
  78. {
  79. $uploads =
  80. isset($backup["remote_uploads"]) && is_array($backup["remote_uploads"])
  81. ? $backup["remote_uploads"]
  82. : [];
  83. if (empty($uploads)) {
  84. return "Nur lokal";
  85. }
  86. $successful = 0;
  87. foreach ($uploads as $upload) {
  88. if (is_array($upload) && !empty($upload["success"])) {
  89. $successful++;
  90. }
  91. }
  92. if ($successful === count($uploads)) {
  93. return "Remote erfolgreich (" . $successful . ")";
  94. }
  95. if ($successful > 0) {
  96. return "Teilweise erfolgreich (" . $successful . "/" . count($uploads) . ")";
  97. }
  98. return "Remote fehlgeschlagen";
  99. }
  100. function settingsGetBackupCapabilityLabel(array $capability): string
  101. {
  102. if (empty($capability["configured"])) {
  103. return "nicht konfiguriert";
  104. }
  105. return !empty($capability["available"]) ? "bereit" : "nicht verfügbar";
  106. }
  107. if (empty($_SESSION['admin_logged_in'])) {
  108. header("Location: login.php");
  109. exit();
  110. }
  111. $pageTitle = "Einstellungen";
  112. $message = "";
  113. $messageType = "";
  114. $backupAutoMessage = "";
  115. $backupAutoMessageType = "";
  116. if ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_settings'])) {
  117. // Validate CSRF token
  118. if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
  119. $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
  120. $messageType = "error";
  121. } else {
  122. $settings = array_merge(getSystemSettings(), [
  123. "order_recipient_email" => $_POST['order_recipient_email'] ?? "",
  124. "attach_order_pdf_to_admin_email" => isset(
  125. $_POST['attach_order_pdf_to_admin_email'],
  126. ),
  127. ]);
  128. if (saveSystemSettings($settings)) {
  129. logAccess("Admin updated system settings");
  130. $message = "Einstellungen wurden gespeichert.";
  131. $messageType = "success";
  132. } else {
  133. $message = "Einstellungen konnten nicht gespeichert werden.";
  134. $messageType = "error";
  135. }
  136. }
  137. } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['create_backup'])) {
  138. if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
  139. $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
  140. $messageType = "error";
  141. } else {
  142. try {
  143. $backup = backupCreate("manual");
  144. $message =
  145. "Backup wurde erstellt: " .
  146. $backup["filename"] .
  147. " (" .
  148. backupFormatBytes((int) $backup["size"]) .
  149. ").";
  150. $messageType = "success";
  151. } catch (Throwable $exception) {
  152. $message = "Backup konnte nicht erstellt werden: " . $exception->getMessage();
  153. $messageType = "error";
  154. }
  155. }
  156. } elseif ($_SERVER['REQUEST_METHOD'] === "GET") {
  157. try {
  158. $backup = backupCreateAutomaticIfDue();
  159. if ($backup !== null) {
  160. $backupAutoMessage =
  161. "Automatisches Backup wurde erstellt: " .
  162. $backup["filename"] .
  163. ".";
  164. $backupAutoMessageType = "success";
  165. }
  166. } catch (Throwable $exception) {
  167. $backupAutoMessage =
  168. "Automatisches Backup konnte nicht erstellt werden: " .
  169. $exception->getMessage();
  170. $backupAutoMessageType = "warning";
  171. }
  172. }
  173. $settings = getSystemSettings();
  174. $updaterStatus = settingsGetUpdaterStatus();
  175. $backupCapabilities = backupRemoteCapabilities();
  176. $backups = backupListBackups();
  177. $bodyClass = "admin-page";
  178. include __DIR__ . "/../includes/header.php";
  179. ?>
  180. <div class="admin-header">
  181. <h2>Einstellungen</h2>
  182. <div>
  183. <a href="index.php" class="btn btn-secondary">Zurück zum Dashboard</a>
  184. </div>
  185. </div>
  186. <?php if ($message !== ""): ?>
  187. <div class="alert alert-<?php echo escape($messageType); ?>">
  188. <?php echo escape($message); ?>
  189. </div>
  190. <?php endif; ?>
  191. <?php if ($backupAutoMessage !== ""): ?>
  192. <div class="alert alert-<?php echo escape($backupAutoMessageType); ?>">
  193. <?php echo escape($backupAutoMessage); ?>
  194. </div>
  195. <?php endif; ?>
  196. <div class="panel panel-lg">
  197. <form method="POST">
  198. <?php echo csrfField(); ?>
  199. <div class="form-group">
  200. <label for="order_recipient_email">Empfängeradresse für interne Bestellungen *</label>
  201. <input type="email" id="order_recipient_email" name="order_recipient_email" required value="<?php echo escape(
  202. $settings["order_recipient_email"],
  203. ); ?>">
  204. </div>
  205. <div class="form-group">
  206. <label class="checkbox-label">
  207. <input type="checkbox" name="attach_order_pdf_to_admin_email" value="1" <?php echo !empty(
  208. $settings["attach_order_pdf_to_admin_email"]
  209. )
  210. ? "checked"
  211. : ""; ?>>
  212. PDF an interne Bestell-E-Mails anhängen
  213. </label>
  214. </div>
  215. <button type="submit" name="save_settings" class="btn">Speichern</button>
  216. </form>
  217. </div>
  218. <div class="panel panel-lg mt-4">
  219. <h3>Backups</h3>
  220. <p>Lokale Aufbewahrung: <?php echo (int) backupGetRetentionLimit(); ?> Backups</p>
  221. <p>Automatisches Intervall: <?php echo (int) floor(((int) BACKUP_AUTO_INTERVAL_SECONDS) / 86400); ?> Tage</p>
  222. <p>
  223. S3: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["s3"])); ?> ·
  224. SFTP: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["sftp"])); ?> ·
  225. Custom: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["custom"])); ?>
  226. </p>
  227. <form method="POST" class="inline-form">
  228. <?php echo csrfField(); ?>
  229. <button type="submit" name="create_backup" class="btn">Backup erstellen</button>
  230. </form>
  231. <h4 class="mt-4">Letzte Backups</h4>
  232. <?php if (empty($backups)): ?>
  233. <p>Es wurden noch keine Backups erstellt.</p>
  234. <?php else: ?>
  235. <div class="table-responsive">
  236. <table class="responsive-table">
  237. <thead>
  238. <tr>
  239. <th>Datei</th>
  240. <th>Erstellt</th>
  241. <th>Auslöser</th>
  242. <th>Größe</th>
  243. <th>Dateien</th>
  244. <th>Remote</th>
  245. </tr>
  246. </thead>
  247. <tbody>
  248. <?php foreach ($backups as $backup): ?>
  249. <tr>
  250. <td data-label="Datei"><?php echo escape($backup["filename"] ?? ""); ?></td>
  251. <td data-label="Erstellt"><?php echo escape(settingsFormatBackupDate((string) ($backup["created_at"] ?? ""))); ?></td>
  252. <td data-label="Auslöser"><?php echo (($backup["trigger"] ?? "") === "automatic") ? "Automatisch" : "Manuell"; ?></td>
  253. <td data-label="Größe"><?php echo escape(backupFormatBytes((int) ($backup["size"] ?? 0))); ?></td>
  254. <td data-label="Dateien"><?php echo (int) ($backup["file_count"] ?? 0); ?></td>
  255. <td data-label="Remote"><?php echo escape(settingsGetBackupUploadLabel($backup)); ?></td>
  256. </tr>
  257. <?php endforeach; ?>
  258. </tbody>
  259. </table>
  260. </div>
  261. <?php endif; ?>
  262. </div>
  263. <div class="panel panel-lg mt-4">
  264. <h3>Updater</h3>
  265. <p>Installierte Version: <?php echo escape(APP_VERSION); ?></p>
  266. <p>Update-Status: <?php echo escape($updaterStatus["label"]); ?></p>
  267. <p><a href="updater.php" class="btn btn-secondary">Updater öffnen</a></p>
  268. </div>
  269. <?php include __DIR__ . "/../includes/footer.php"; ?>