dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
dbxApi.php
Go to the documentation of this file.
1<?php
10
11//include_once $this->os_path($this->get_base_dir().'dbx/add_ons/sftp/vendor/autoload.php');
12//use phpseclib3\Crypt\AES;
13use \phpseclib3\Crypt\AES;
14
16
18 return function_exists('dbx') ? (int) dbx()->log_missing($missing) : 0;
19}
20
39class dbxApi {
40
42 public array $editor_files = array();
43
45 private array $owner_stack = array();
46
48 private bool $sys_msg_running = false;
49
51 private array $timer_state = array();
52
54 private array $admin_bypass_user = array();
55
57 private bool $admin_bypass_user_loaded = false;
58
60 private bool $admin_bypass_user_loading = false;
61
71 private function push_owner($owner): void {
72 if (is_object($owner)) {
73 $this->owner_stack[] = $owner;
74 }
75 }
76
82 private function pop_owner(): void {
83 if ($this->owner_stack) {
84 array_pop($this->owner_stack);
85 }
86 }
87
97 private function set_current_owner($owner): void {
98 if (is_object($owner)) {
99 if ($this->owner_stack) {
100 $this->owner_stack[count($this->owner_stack) - 1] = $owner;
101 } else {
102 $this->owner_stack[] = $owner;
103 }
104 }
105 }
106
112 public function get_current_owner() {
113 if (!$this->owner_stack) {
114 return null;
115 }
116
117 return $this->owner_stack[count($this->owner_stack) - 1];
118 }
119
134 public function run_owner($owner, string $method = 'run', ...$args) {
135 if (!is_object($owner) || !is_callable(array($owner, $method))) {
136 return null;
137 }
138
139 $this->push_owner($owner);
140
141 try {
142 return $owner->$method(...$args);
143 } finally {
144 $this->pop_owner();
145 }
146 }
147
166 public function get_system_obj(string $class, string $use = ''): ?object {
167 global $_dbxCache;
168
169 if (!preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', $class)) {
170 throw new Exception("Invalid system class name '$class'.");
171 }
172
173 if (isset($_dbxCache[$class])) {
174 return !$use ? $_dbxCache[$class] : null;
175 }
176
177 $baseClass = '\\' . $class;
178 $baseFile = $this->os_path($this->get_base_dir() . "dbx/include/" . $class . ".class.php");
179
180 if (file_exists($baseFile)) {
181 require_once $baseFile;
182 } else {
183 $baseClass = "\\dbxUndefClass";
184 }
185
186 $myClass = $this->get_SysClassOverrideName($class);
187 $myFile = $this->ensure_SysClassOverride($class, $myClass, $baseClass);
188
189 if ($myFile && file_exists($myFile)) {
190 $this->register_editor_file('sysclass', $myFile);
191 require_once $myFile;
192 }
193
194 $myClassFull = '\\' . $myClass;
195 $createClass = class_exists($myClassFull, false) ? $myClassFull : $baseClass;
196
197 if ($use) {
198 return null;
199 }
200
201 if (class_exists($createClass)) {
202 $_dbxCache[$class] = new $createClass();
203 return $_dbxCache[$class];
204 }
205
206 throw new Exception("Klasse '$createClass' konnte nicht geladen werden.");
207 }
208
215 public function editor_file_path(string $file): string {
216 $file = str_replace('\\', '/', $file);
217 $base = str_replace('\\', '/', $this->get_base_dir());
218
219 if (strpos($file, $base) === 0) {
220 $file = substr($file, strlen($base));
221 }
222
223 return ltrim($file, '/');
224 }
225
233 public function register_editor_file(string $kind, string $file): void {
234 $kind = strtolower(trim($kind));
235 $file = trim($file);
236
237 if ($kind === '' || $file === '') {
238 return;
239 }
240
241 $path = $this->editor_file_path($file);
242 $key = $kind . '|' . $path;
243 $this->editor_files[$key] = array('kind' => $kind, 'file' => $path);
244 }
245
251 public function get_editor_files(): array {
252 return $this->editor_files;
253 }
254
269 public function editor_marker(string $kind, string $file): string {
270 $kind = strtolower(trim($kind));
271 $mode = (int) $this->get_system_var('dbx_edit', 0, 'int');
272 $modes = array('fd' => 4, 'dd' => 5, 'class' => 6, 'sysclass' => 7, 'config' => 8);
273
274 if (!isset($modes[$kind]) || ($mode !== 9 && $mode !== $modes[$kind]) || $file === '') {
275 return '';
276 }
277
278 $path = $this->editor_file_path($file);
279 $path = str_replace('--', '-', $path);
280
281 return "\n<!-- DBX-EDITOR|$kind|$path -->\n";
282 }
283
303 public function get_modul_obj(string $class): object {
304 // Vollqualifizierten Klassennamen vorbereiten
305 $namespace_class = '\dbx\-class-\-class-';
306 $namespace_class = str_replace('-class-', $class, $namespace_class);
307
308 // Modul-ID auslesen und inkrementieren
309 $modul_id = $this->get_system_var('dbx_activ_modul_id', 0, '*');
310 $modul_id++;
311 $this->set_system_var('dbx_activ_modul_id', $modul_id);
312
313 // Modulname in System- und Modulvariablen speichern
314 $this->set_system_var('dbx_activ_modul', $class);
315 $this->set_modul_var('dbx_modul_id', $modul_id);
316 $this->set_modul_var('dbx_modul', $class);
317
318 // Admin-spezifisches Design anwenden, falls Modul ein Admin-Modul ist
319 if (stripos($class, 'admin') !== false) {
320 //$admin_design = $this->get_config('dbx', 'default_design_admin');
321 //$this->set_system_var('dbx_design', $admin_design);
322 }
323
324 // Pfad zur Klassen-Datei des Moduls berechnen
325 $modul_class_file = $this->os_path($this->get_base_dir() . "dbx/modules/$class/$class.class.php");
326
327 // Klassen-Datei einbinden, wenn vorhanden
328 if (file_exists($modul_class_file)) {
329 $this->register_editor_file('class', $modul_class_file);
330 require_once $modul_class_file;
331 } else {
332 // Fallback-Klasse verwenden, falls die Datei fehlt
333 $namespace_class = "\\dbxUndefClass";
334 }
335
336 // Prüfen, ob die Klasse existiert, und Instanz erstellen
337 if (class_exists($namespace_class)) {
338 $object = new $namespace_class();
339 if (method_exists($object, 'set_editor_class_file')) {
340 $object->set_editor_class_file($modul_class_file);
341 }
342 $this->set_current_owner($object);
343 return $object;
344 }
345
346 // Fehler werfen, falls die Klasse nicht existiert
347 throw new Exception("Modul-Klasse '$namespace_class' konnte nicht geladen werden.");
348 }
349
370 public function get_include_obj(string $class, string $modul = '', string $use = ''): ?object {
371 // Aktuelles Modul verwenden, wenn keins angegeben wurde
372 if (!$modul) {
373 $modul = $this->get_system_var('dbx_activ_modul', 'dbx', '*');
374 }
375
376 // Systemvariable für das aktuell geladene Include setzen
377 $this->set_system_var('dbx_inc', $class);
378
379 // Vollqualifizierten Klassennamen generieren
380 $namespace_class = '\dbx\-modul-\-class-';
381 $namespace_class = str_replace('-modul-', $modul, $namespace_class);
382 $namespace_class = str_replace('-class-', $class, $namespace_class);
383
384 // Pfad zur Klassen-Datei bestimmen
385 $modul_class_file = $this->os_path($this->get_base_dir() . "dbx/modules/$modul/include/$class.class.php");
386
387 // Klassen-Datei einbinden, wenn sie existiert
388 if (file_exists($modul_class_file)) {
389 $this->register_editor_file('class', $modul_class_file);
390 require_once $modul_class_file;
391 } else {
392 // Fallback-Klasse verwenden, falls Datei fehlt
393 $namespace_class = "\\dbxUndefClass";
394 }
395
396 // Objekt erstellen und zurückgeben, falls $use nicht gesetzt ist
397 if (!$use) {
398 if (class_exists($namespace_class)) {
399 $object = new $namespace_class();
400 if (method_exists($object, 'set_editor_class_file')) {
401 $object->set_editor_class_file($modul_class_file);
402 }
403 $this->set_current_owner($object);
404 return $object;
405 }
406
407 // Fehler werfen, falls die Klasse nicht existiert
408 throw new Exception("Klasse '$namespace_class' konnte nicht geladen werden.");
409 }
410
411 // Keine Rückgabe, wenn $use gesetzt ist
412 return null;
413 }
414
426 public function use_system_class($class) {
427 $modul_id=0;
428 $dbx_class_file=$this->get_base_dir()."dbx/include/".$class.".class.php";
429 $dbx_class_file=$this->os_path($dbx_class_file);
430
431
432 if (file_exists($dbx_class_file)) {
433 require_once $dbx_class_file;
434 }
435 }
436
454 public function get_system_var(string $varname, $default = '', string $rules = '*') {
455 // Initialisierung der Rückgabevariable
456 $value = $default;
457 $danger_value = '';
458
459 // Überprüfen, ob die Variable in der Session vorhanden ist
460 if (isset($_SESSION['dbx']['tmp'][0]['dbx'][$varname])) {
461 $danger_value = $_SESSION['dbx']['tmp'][0]['dbx'][$varname];
462 } else {
463 // Wenn nicht, nach der Variable in GET oder POST suchen
464 if (isset($_GET[$varname])) {
465 $danger_value = $_GET[$varname];
466 }
467 if (isset($_POST[$varname])) {
468 $danger_value = $_POST[$varname];
469 }
470 }
471
472 // Wenn ein Wert vorhanden und gültig ist, validieren und zurückgeben
473 if (($danger_value !== '') && ($danger_value !== null)) {
474 if (dbx_validate_var($danger_value, $rules, $varname)) {
475 $value = $danger_value;
476 }
477 }
478
479 // Rückgabe des validierten Werts oder des Standardwerts
480 return $value;
481 }
482
498 public function set_system_var(string $varname, $value) {
499 // Speichert den Wert der Systemvariable in der Session
500 $_SESSION['dbx']['tmp'][0]['dbx'][$varname] = $value;
501 }
502
519 public function get_modul_var($varname, $default = '', $rules = 'alphanum') {
520 // Standardwert initialisieren
521 $value = $default;
522
523 // Das aktive Modul und die Modul-ID holen
524 $modul = $this->get_system_var('dbx_activ_modul', 'undef', '*');
525 $mid = $this->get_system_var('dbx_activ_modul_id', 88888, '*');
526
527 // Versuchen, die Variable aus der Session zu holen
528 if (isset($_SESSION['dbx']['tmp'][$mid][$modul][$varname])) {
529 $danger_value = $_SESSION['dbx']['tmp'][$mid][$modul][$varname];
530 } else {
531 // Wenn nicht in der Session, versuche GET und POST
532 $danger_value = '';
533
534 if (isset($_GET[$varname])) {
535 $danger_value = $_GET[$varname];
536 }
537
538 if (isset($_POST[$varname])) {
539 $danger_value = $_POST[$varname];
540 }
541 }
542
543 // Wenn ein Wert vorhanden ist und er gültig ist, validiere den Wert
544 if ($danger_value !== '' && $danger_value !== null && dbx_validate_var($danger_value, $rules, $varname)) {
545 $value = $danger_value;
546 }
547
548 // Rückgabe des Werts (entweder der gefundene gültige Wert oder der Standardwert)
549 return $value;
550 }
551
569 public function set_modul_var($varname, $value = null, $check_protected = true) {
570 // Das aktive Modul und die Modul-ID holen
571 $mid = $this->get_system_var('dbx_activ_modul_id', 0, 'int');
572 $modul = $this->get_system_var('dbx_activ_modul', 'dbx', 'parameter');
573
574 // Geschützte ModulVariablen prüfen.
575 // Wichtig: Schutzliste nur aus der echten ModulVar-Session lesen,
576 // nicht ueber $this->get_modul_var(), damit GET/POST hier niemals mitreden.
577 if ($check_protected) {
578 $protected = array();
579 if (isset($_SESSION['dbx']['tmp'][$mid][$modul]['dbx_protected_modulvars'])) {
580 $protected = $_SESSION['dbx']['tmp'][$mid][$modul]['dbx_protected_modulvars'];
581 }
582 if (is_array($protected) && array_key_exists($varname, $protected)) {
583 dbx()->debug("PROTECTED ($varname)");
584 return;
585 }
586 }
587
588 // Setze den Wert in der Session
589 $_SESSION['dbx']['tmp'][$mid][$modul][$varname] = $value;
590
591 // Optional: Debugging-Informationen hinzufügen
592 // dbx_debug("dbx_set_ModulVar modul=($modul) Mod=($mid) Var=($varname) val=($value)");
593 }
594
598 public function get_request_var(string $varname, $default = '', string $rules = 'parameter') {
599 return $this->get_system_obj('dbxRequest')->request($varname, $default, $rules);
600 }
601
620 public function get_config(string $modul = 'dbx', string $key = '', $default = null) {
621 $moduleConfigFile = $this->os_path($this->get_base_dir() . "dbx/modules/$modul/cfg/config.php");
622 $moduleLocalConfigFile = $this->os_path($this->get_base_dir() . "dbx/modules/$modul/cfg/config.local.php");
623
624 if (file_exists($moduleConfigFile)) {
625 $_SESSION['dbx']['config_file'][$modul] = $moduleConfigFile;
626 $this->register_editor_file('config', $moduleConfigFile);
627 }
628
629 $signature = $this->config_file_signature($moduleConfigFile)
630 . '|' . $this->config_file_signature($moduleLocalConfigFile);
631 $cachedSignature = (string)($_SESSION['dbx']['config_signature'][$modul] ?? '');
632
633 // Der Cache gilt nur so lange, wie Basis- und lokale Konfiguration
634 // unveraendert sind. Das verhindert veraltete Werte in langen Sessions.
635 if (!isset($_SESSION['dbx']['config'][$modul]) || $cachedSignature !== $signature) {
636 $config = $this->read_config_file($moduleConfigFile);
637 $localConfig = $this->read_config_file($moduleLocalConfigFile);
638 $localConfig = $this->normalize_legacy_install_config($modul, $moduleLocalConfigFile, $localConfig);
639 if ($localConfig) {
640 $config = array_replace_recursive($config, $localConfig);
641 }
642
643 if (!isset($config['groups'])) {
644 $config['groups'] = array('admin');
645 } elseif (!is_array($config['groups'])) {
646 $config['groups'] = array_values(array_filter(array_map('trim', explode(',', (string)$config['groups']))));
647 }
648
649 $_SESSION['dbx']['config'][$modul] = $config;
650 $_SESSION['dbx']['config_signature'][$modul] = $signature;
651 }
652
653 $config = $_SESSION['dbx']['config'][$modul];
654
655 // Spezifischen Schlüssel zurueckgeben, falls angegeben
656 if ($key) {
657 if (!array_key_exists($key, $config)) {
658 return $default !== null ? $default : 'undef';
659 }
660
661 $val = $config[$key];
662 if (($val === 'undef' || $val === '' || $val === null) && $default !== null) {
663 return $default;
664 }
665
666 return $val;
667 }
668
669 // Gesamte Konfiguration zurückgeben
670 return $config;
671 }
672
679 private function read_module_config_defaults(string $modul): array {
680 if ($modul === 'dbx') {
681 $dir_file = $this->os_path($this->get_base_dir() . 'dbx/modules/dbx/cfg/config.php');
682 } else {
683 $dir_file = $this->os_path($this->get_base_dir() . "dbx/modules/$modul/cfg/config.php");
684 }
685 if (!is_file($dir_file) || !is_readable($dir_file)) {
686 return array();
687 }
688
689 return $this->read_config_file($dir_file);
690 }
691
698 private function read_config_file(string $dir_file): array {
699 if (!is_file($dir_file) || !is_readable($dir_file)) {
700 return array();
701 }
702
703 $config = array();
704 $content = file_get_contents($dir_file);
705 if (!is_string($content) || $content === '') {
706 return array();
707 }
708
709 $clean_code = str_replace(array('<?php', '?>'), '', $content);
710 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
711 throw new \Exception("Fehler in config.php: $errstr in Zeile $errline");
712 });
713
714 try {
715 eval($clean_code);
716 } catch (\Throwable $e) {
717 $this->debug('#CFG read failed file=(' . $dir_file . ') error=(' . $e->getMessage() . ')');
718 $config = array();
719 } finally {
720 restore_error_handler();
721 }
722
723 return is_array($config) ? $config : array();
724 }
725
735 private function normalize_legacy_install_config(string $modul, string $localFile, array $localConfig): array {
736 if ($modul === 'dbx' && is_file($localFile) && !array_key_exists('install', $localConfig)) {
737 $localConfig['install'] = 0;
738 }
739
740 return $localConfig;
741 }
742
744 private function config_file_signature(string $file): string {
745 if (!is_file($file)) {
746 return '-';
747 }
748
749 $mtime = @filemtime($file);
750 $size = @filesize($file);
751 return (string)($mtime === false ? 0 : $mtime) . ':' . (string)($size === false ? 0 : $size);
752 }
753
760 private function strip_local_config_values(array $runtime, array $local, array $base): array {
761 foreach ($local as $name => $localValue) {
762 if (is_array($localValue) && isset($runtime[$name]) && is_array($runtime[$name])) {
763 $baseValue = isset($base[$name]) && is_array($base[$name]) ? $base[$name] : array();
764 $runtime[$name] = $this->strip_local_config_values($runtime[$name], $localValue, $baseValue);
765 if ($runtime[$name] === array() && !array_key_exists($name, $base)) {
766 unset($runtime[$name]);
767 }
768 continue;
769 }
770
771 if (array_key_exists($name, $base)) {
772 $runtime[$name] = $base[$name];
773 } else {
774 unset($runtime[$name]);
775 }
776 }
777
778 return $runtime;
779 }
780
793 public function set_config(string $modul, array $config): int {
794 $content = "<?php \n"; // PHP-Tag hinzufügen, um die Datei als ausführbaren Code zu speichern
795 $dir = $this->get_base_dir() . "dbx/modules/$modul/cfg/";
796 if (isset($config['form-config-edit'])) unset($config['form-config-edit']);
797 $dir_file = $this->os_path($dir . 'config.php');
798 $local_file = $this->os_path($dir . 'config.local.php');
799 $baseConfig = $this->read_config_file($dir_file);
800 $localConfig = $this->read_config_file($local_file);
801 if ($localConfig) {
802 $config = $this->strip_local_config_values($config, $localConfig, $baseConfig);
803 }
804 $configStore = $this->get_system_obj('dbxConfigStore');
805 $config = $configStore->normalize_for_store($config);
806 $dir = $this->os_path($dir);
807
808 // Konfigurationsarray in PHP-Code konvertieren
809 if (is_array($config)) {
810 $content .= dbx_convertArrayToPHPCode($config, '$config'); // Array in PHP-Code umwandeln
811 }
812
813 // Verzeichnis erstellen, falls es nicht existiert
814 if (!is_dir($dir)) {
815 mkdir($dir, 0700, true);
816 }
817
818 // Dateiinhalt schreiben und Erfolg prüfen
819 $ok = file_put_contents($dir_file, $content);
820 dbx()->debug("#CFG write ok=($ok) file=($dir_file)");
821 if ($ok) {
822 $runtimeConfig = $localConfig ? array_replace_recursive($config, $localConfig) : $config;
823 $_SESSION['dbx']['config'][$modul] = $runtimeConfig;
824 $_SESSION['dbx']['config_signature'][$modul]
825 = $this->config_file_signature($dir_file) . '|' . $this->config_file_signature($local_file);
826 $_SESSION['dbx']['config_file'][$modul] = $dir_file;
827 $this->register_editor_file('config', $dir_file);
828 }
829
830
831 return $ok ?: 0; // Gibt 0 zurück, falls `file_put_contents` fehlschlägt
832 }
833
841 public function set_local_config(string $modul, array $localConfig): int {
842 if (preg_match('/^[A-Za-z0-9_]+$/', $modul) !== 1) {
843 return 0;
844 }
845
846 $dir = $this->os_path($this->get_base_dir() . "dbx/modules/$modul/cfg/");
847 if (!is_dir($dir) && !mkdir($dir, 0700, true) && !is_dir($dir)) {
848 return 0;
849 }
850
851 $localFile = $this->os_path($dir . 'config.local.php');
852 $content = "<?php\n"
853 . dbx_convertArrayToPHPCode($localConfig, '$config');
854 $written = file_put_contents($localFile, $content, LOCK_EX);
855 if ($written === false) {
856 return 0;
857 }
858
859 @chmod($localFile, 0600);
860 unset(
861 $_SESSION['dbx']['config'][$modul],
862 $_SESSION['dbx']['config_signature'][$modul]
863 );
864 $this->get_config($modul);
865
866 return (int)$written;
867 }
868
875 public function patch_local_config(string $modul, array $patch): int {
876 if (preg_match('/^[A-Za-z0-9_]+$/', $modul) !== 1) {
877 return 0;
878 }
879
880 $localFile = $this->os_path(
881 $this->get_base_dir() . "dbx/modules/$modul/cfg/config.local.php"
882 );
883 $localConfig = $this->read_config_file($localFile);
884 $localConfig = array_replace_recursive($localConfig, $patch);
885
886 return $this->set_local_config($modul, $localConfig);
887 }
888
897 string $modul,
898 string $section,
899 array $value
900 ): int {
901 if (preg_match('/^[A-Za-z0-9_]+$/', $modul) !== 1
902 || preg_match('/^[A-Za-z0-9_]+$/', $section) !== 1
903 ) {
904 return 0;
905 }
906
907 $localFile = $this->os_path(
908 $this->get_base_dir() . "dbx/modules/$modul/cfg/config.local.php"
909 );
910 $localConfig = $this->read_config_file($localFile);
911 $localConfig[$section] = $value;
912
913 return $this->set_local_config($modul, $localConfig);
914 }
915
940 public function send_mail($from, $to, string $subject = '', string $body = '', string $format = 'html', $attachments = array(), array $options = array()): int {
941 $mail = $this->get_system_obj('dbxMail');
942 if (!$mail) {
943 return 0;
944 }
945
946 $mail->init();
947 $options['from'] = $from;
948
949 $format = strtolower(trim($format));
950 if ($format === 'txt') {
951 $format = 'text';
952 }
953
954 if ($format === 'html') {
955 $mail->bodyhtml($body);
956 if (isset($options['text'])) {
957 $mail->bodytext((string) $options['text']);
958 }
959 } else {
960 $mail->bodytext($body);
961 }
962
963 foreach ($this->normalize_mail_attachments($attachments) as $attachment) {
964 if (is_array($attachment)) {
965 $mail->attachfile(
966 (string) ($attachment['path'] ?? $attachment['file'] ?? ''),
967 (string) ($attachment['disposition'] ?? 'attachment'),
968 (string) ($attachment['content_type'] ?? $attachment['type'] ?? ''),
969 (string) ($attachment['cid'] ?? '')
970 );
971 } else {
972 $mail->attachfile((string) $attachment);
973 }
974 }
975
976 return (int) $mail->send($to, $subject, $options);
977 }
978
979 private function normalize_mail_attachments($attachments): array {
980 if ($attachments === null || $attachments === '') {
981 return array();
982 }
983
984 if (is_string($attachments)) {
985 return array_filter(array_map('trim', preg_split('/[;,]+/', $attachments)));
986 }
987
988 if (is_array($attachments)) {
989 if (isset($attachments['path']) || isset($attachments['file'])) {
990 return array($attachments);
991 }
992 return $attachments;
993 }
994
995 return array();
996 }
997
1014 public function get_remember_var(string $varname, $default = '', string $modul = 'modul') {
1015 // Initialisierung der Rückgabevariable
1016 $value = $default;
1017 $danger_value = '';
1018
1019 // Wenn das Modul nicht angegeben ist, den aktiven Modulnamen aus der Session holen
1020 if ($modul == 'modul') {
1021 $modul = $this->get_system_var('dbx_activ_modul', 'dbx', '*');
1022 }
1023
1024 // Überprüfen, ob die Variable in der Session unter der richtigen Modul-Sektion existiert
1025 if (isset($_SESSION['dbx']['remember'][$modul][$varname])) {
1026 $value = $_SESSION['dbx']['remember'][$modul][$varname];
1027 }
1028
1029 // Rückgabe des validierten Werts oder des Standardwerts
1030 return $value;
1031 }
1032
1049 public function set_remember_var(string $varname, $value, string $modul = 'modul') {
1050 // Wenn das Modul nicht angegeben ist, den aktiven Modulnamen aus der Session holen
1051 if ($modul == 'modul') {
1052 $modul = $this->get_system_var('dbx_activ_modul', 'dbx', '*');
1053 }
1054
1055 // Setzt den Wert der Variable in der Session unter der "remember"-Sektion
1056 $_SESSION['dbx']['remember'][$modul][$varname] = $value;
1057
1058 // Wenn das Modul 'dbx' ist, wird der Wert auch in der System-Session gespeichert
1059 if ($modul == 'dbx') {
1060 $this->set_system_var($varname, $value);
1061 }
1062 }
1063
1078 public function get_session_var($key,$default=null,$section='sys',$modul='modul') {
1079 $val=$default;
1080 if ($modul=='modul') $modul =$this->get_system_var('dbx_activ_modul' ,'dbx');
1081 if ($key != '*') {
1082 if (isset($_SESSION['dbx']['session'][$modul][$section][$key])) {
1083 $val=$_SESSION['dbx']['session'][$modul][$section][$key];
1084 }
1085 } else {
1086 if (isset($_SESSION['dbx']['session'][$modul][$section])) {
1087 $val=$_SESSION['dbx']['session'][$modul][$section];
1088 }
1089 }
1090 return $val;
1091 }
1092
1102 public function set_session_var($key,$val,$section='sys',$modul='') {
1103 if (!$modul) $modul =$this->get_system_var('dbx_activ_modul' ,'dbx');
1104 if ($key != '*') $_SESSION['dbx']['session'][$modul][$section][$key]=$val;
1105 if ($key == '*') $_SESSION['dbx']['session'][$modul][$section]=$val;
1106 }
1107
1115 public function delete_session_var($key,$section='sys',$modul='modul') {
1116 if ($modul=='modul') $modul =$this->get_system_var('dbx_activ_modul' ,'dbx');
1117 if ($key != '*') {
1118 if (isset($_SESSION['dbx']['session'][$modul][$section][$key])) {
1119 unset($_SESSION['dbx']['session'][$modul][$section][$key]);
1120 }
1121 }
1122 if ($key == '*') {
1123 if (isset($_SESSION['dbx']['session'][$modul][$section])) {
1124 unset($_SESSION['dbx']['session'][$modul][$section]);
1125 }
1126 }
1127 if ($key == '*' && $section=='*') {
1128 if (isset($_SESSION['dbx']['session'][$modul])) {
1129 unset($_SESSION['dbx']['session'][$modul]);
1130 }
1131 }
1132 //dbx_debug("DEL Session Store Key=($key) section=($section) Modul=($modul)");
1133
1134 }
1135
1145 private function normalize_action_scope(string $scope): string {
1146 return preg_replace('/[^a-zA-Z0-9_.:-]/', '', $scope) ?: 'global';
1147 }
1148
1158 private function action_token_secret(): string {
1159 $secret = (string)$this->get_session_var('action_token_secret', '', 'security', 'dbx');
1160
1161 if (!preg_match('/^[a-f0-9]{64}$/', $secret)) {
1162 $secret = bin2hex(random_bytes(32));
1163 $this->set_session_var('action_token_secret', $secret, 'security', 'dbx');
1164 }
1165
1166 return $secret;
1167 }
1168
1189 public function action_token(string $scope = 'global'): string {
1190 $scope = $this->normalize_action_scope($scope);
1191 return hash_hmac('sha256', 'dbx-action-v2|' . $scope, $this->action_token_secret());
1192 }
1193
1206 public function check_action_token(string $scope = 'global', string $token = ''): bool {
1207 if (!preg_match('/^[a-f0-9]{64}$/', $token)) {
1208 return false;
1209 }
1210
1211 $scope = $this->normalize_action_scope($scope);
1212
1213 // Kompatibilitaet fuer Links, die vor dem HMAC-Wechsel gerendert wurden.
1214 // Wichtig: Bei unbekannten Scopes wird hier kein neuer Eintrag erzeugt.
1215 $legacyTokens = $this->get_session_var('action_tokens', array(), 'security', 'dbx');
1216 if (is_array($legacyTokens)
1217 && isset($legacyTokens[$scope])
1218 && preg_match('/^[a-f0-9]{64}$/', (string)$legacyTokens[$scope])
1219 && hash_equals((string)$legacyTokens[$scope], $token)) {
1220 return true;
1221 }
1222
1223 // Eine Pruefung darf niemals erst ein Secret und damit Sessionzustand
1224 // erzeugen. Das Secret entsteht ausschliesslich beim Rendern eines
1225 // gueltigen Aktionslinks durch action_token().
1226 $secret = (string)$this->get_session_var('action_token_secret', '', 'security', 'dbx');
1227 if (!preg_match('/^[a-f0-9]{64}$/', $secret)) {
1228 return false;
1229 }
1230
1231 $expected = hash_hmac('sha256', 'dbx-action-v2|' . $scope, $secret);
1232 return hash_equals($expected, $token);
1233 }
1234
1247 public function invalidate_action_tokens(): void {
1248 $this->delete_session_var('action_token_secret', 'security', 'dbx');
1249 $this->delete_session_var('action_tokens', 'security', 'dbx');
1250 }
1251
1270 public function action_url(string $url, string $action = '', array $bindings = array()): string {
1271 $webApp = $this->get_system_obj('dbxWebApp');
1272 if (!is_object($webApp)) {
1273 return $url;
1274 }
1275
1276 $scope = '';
1277 if ($action !== '') {
1278 $scope = (string)$webApp->action_scope_for_url($url, $action, $bindings);
1279 } else {
1280 $policy = $webApp->action_policy_for_url($url);
1281 $scope = is_array($policy) ? (string)($policy['scope'] ?? '') : '';
1282 }
1283
1284 if ($scope === '') {
1285 return $url;
1286 }
1287
1288 return (string)$webApp->append_route_params($url, array(
1289 'dbx_token' => $this->action_token($scope),
1290 ));
1291 }
1292
1305 public function user($key='id') {
1306 $current_user = $_SESSION['dbx']['current_user'] ?? array();
1307
1308 if (defined('dbxRunAsAdmin') && (int) constant('dbxRunAsAdmin') === 1) {
1309 $current_user = $this->get_admin_bypass_user($current_user);
1310 }
1311
1312 if ($key === '*') {
1313 return $current_user;
1314 }
1315
1316 return $current_user[$key] ?? null;
1317 }
1318
1329 private function get_admin_bypass_user(array $session_user = array()): array {
1330 if ((int)($session_user['id'] ?? 0) === 1) {
1331 return $session_user;
1332 }
1333
1334 if ($this->admin_bypass_user_loaded || $this->admin_bypass_user_loading) {
1335 return $this->admin_bypass_user;
1336 }
1337
1338 $this->admin_bypass_user = array_merge($session_user, array(
1339 'id' => 1,
1340 'uname' => 'admin',
1341 'roles' => 'admin',
1342 'email' => '',
1343 'name' => 'Admin',
1344 'design' => $session_user['design'] ?? 'default',
1345 'color' => $session_user['color'] ?? 'default',
1346 'language' => $session_user['language'] ?? 'de',
1347 'edit' => $session_user['edit'] ?? 0,
1348 ));
1349 $this->admin_bypass_user_loading = true;
1350
1351 try {
1352 $session = $this->get_system_obj('dbxSession');
1353 if (is_object($session) && method_exists($session, 'get_current_user')) {
1354 $admin_user = $session->get_current_user(1);
1355 if (is_array($admin_user) && (int)($admin_user['id'] ?? 0) === 1) {
1356 $this->admin_bypass_user = $admin_user;
1357 }
1358 }
1359 } catch (\Throwable $e) {
1360 // Der sichere Admin-Fallback bleibt auch ohne verfuegbare DB erhalten.
1361 } finally {
1362 $this->admin_bypass_user_loading = false;
1363 $this->admin_bypass_user_loaded = true;
1364 }
1365
1366 return $this->admin_bypass_user;
1367 }
1368
1381 public function can($access_groups = '', $user_groups = '') {
1382 $access = 0;
1383 if (defined('dbxRunAsAdmin') && (int) constant('dbxRunAsAdmin') === 1) return 1;
1384 if ($access_groups=='*') return 1;
1385 if (!$access_groups) return 1;
1386 $current_user_groups = !$user_groups;
1387 if ($current_user_groups) $user_groups = $_SESSION['dbx']['current_user']['roles'] ?? '';
1388
1389 if (!is_array($user_groups)) $user_groups = explode(',', $user_groups);
1390 if (!is_array($access_groups)) $access_groups = explode(',', $access_groups);
1391 $user_groups = array_map('trim', $user_groups);
1392 $access_groups = array_map('trim', $access_groups);
1393
1394 if ($current_user_groups && in_array('authenticated', $access_groups, true) && (int)$this->user() > 0) {
1395 return 1;
1396 }
1397
1398 foreach ($user_groups as $role) {
1399 if ($role === 'admin') return 1; // Immer Zugriff für Admins
1400
1401 foreach ($access_groups as $group) {
1402 if ($group === '*' || $group === $role) $access = 1;
1403 if ($access) break 2; // Beide Schleifen abbrechen
1404 }
1405 }
1406
1407 return $access;
1408 }
1409
1410 public function has_group($access_groups = '', $user_groups = '') {
1411 return $this->can($access_groups, $user_groups);
1412 }
1413
1419 public function is_dbx_edit(): bool {
1420 return (int) $this->get_system_var('dbx_edit', 0, 'int') > 0;
1421 }
1422
1423
1430 public function can_modul($modul) {
1431
1432 $access=0;
1433
1434 $current_user= $_SESSION['dbx']['current_user'] ?? array();
1435 $modul_config= $this->get_config($modul);
1436 $groups =$modul_config['groups'] ?? '';
1437 $uid =$current_user['id'] ?? 0;
1438 $install=$this->get_system_var('dbx_install',0,'int');
1439
1440 if (defined('dbxRunAsAdmin') && (int) constant('dbxRunAsAdmin') === 1) {
1441 return 1;
1442 }
1443 if ((int)$uid === 1) {
1444 return 1;
1445 }
1446
1447 $access = $install ? 1 : $this->can($groups);
1448
1449 if ($access==0) $this->set_system_var('dbx_noaccess_modul',"(User=$uid Modul=$modul)");
1450 return $access;
1451 }
1452
1465 public function login($uid=0,$remember=0) {
1466 $old=$this->user();
1467 dbx()->debug("API dbx_login von ($old) Zu ($uid)");
1468 if ($uid != $old) {
1469 $oSession=$this->get_system_obj('dbxSession');
1470 $oSession->login($uid,$remember);
1471
1472 $page = $this->get_base_url();
1473 $from = $this->user('email');
1474 $fromname = $this->user('name');
1475 $subject = 'Login ('.$from.') on ('.$page.') User=('.$uid.')';
1476 $text = $subject;
1477 //$this->sys_msg('info','login',$uid,$subject,'ok');
1478 //dbx_sendMail($from,$fromname,'login@dbxapp.de',$subject,$text,'text'); // #todo
1479
1480 }
1481 }
1482
1488 public function get_base_url() {
1489 return $this->get_system_var('dbx_base_url','','*');
1490 }
1491
1497 public function get_self_url() {
1498 return $this->get_system_var('dbx_self_url','','*');
1499 }
1500
1507 public function get_base_dir(int $cutData = 0): string {
1508 if (function_exists('dbx_get_base_dir')) {
1509 return (string) dbx_get_base_dir($cutData);
1510 }
1511
1512 $path = str_replace('\\', '/', dirname(__DIR__, 2)) . '/';
1513 if ($cutData) {
1514 $path = str_ends_with($path, '/Data/') ? substr($path, 0, -5) : $path;
1515 }
1516 return rtrim($path, '/') . '/';
1517 }
1518
1524 public function get_file_dir(): string {
1525 if (function_exists('dbx_get_file_dir')) {
1526 return (string) dbx_get_file_dir();
1527 }
1528
1529 return $this->get_base_dir() . 'files/';
1530 }
1531
1538 public function os_path(string $path): string {
1539 $path = str_replace(array('\\', '//', '\\\\'), '/', $path);
1540 $path = preg_replace('#(?<!:)//+#', '/', $path);
1541 if (DIRECTORY_SEPARATOR === '\\') {
1542 $path = str_replace('/', '\\', $path);
1543 }
1544
1545 $separator = DIRECTORY_SEPARATOR;
1546 if (!str_ends_with($path, $separator) && !str_contains(basename($path), '.')) {
1547 $path .= $separator;
1548 }
1549 return $path;
1550 }
1551
1553 private function path_is_absolute(string $path): bool {
1554 $path = str_replace('\\', '/', trim($path));
1555 if ($path === '') return false;
1556 if ($path[0] === '/') return true;
1557 return (bool)preg_match('#^[A-Za-z]:/#', $path);
1558 }
1559
1561 public function config_path_store(string $path, bool $dirTrailingSlash = false): string {
1562 $path = str_replace('\\', '/', trim($path));
1563 if ($path === '') return '';
1564
1565 $base = str_replace('\\', '/', $this->get_base_dir());
1566 if ($this->path_is_absolute($path) || str_starts_with($path, $base)) {
1567 $absolute = str_replace('\\', '/', $this->os_path($path));
1568 $baseNormalized = str_replace('\\', '/', $this->os_path($base));
1569 if (str_starts_with($absolute, $baseNormalized)) {
1570 $path = substr($absolute, strlen($baseNormalized));
1571 }
1572 }
1573
1574 $path = ltrim($path, '/');
1575 if ($dirTrailingSlash && $path !== '') {
1576 $path = rtrim($path, '/') . '/';
1577 }
1578 return $path;
1579 }
1580
1582 public function config_path_resolve(string $path): string {
1583 $path = str_replace('\\', '/', trim($path));
1584 if ($path === '') return '';
1585 if (!$this->path_is_absolute($path)) {
1586 $path = $this->get_base_dir() . ltrim($path, '/');
1587 }
1588 return $this->os_path($path);
1589 }
1590
1592 public function error_log_file(): string {
1593 $dir = rtrim($this->get_file_dir(), '/\\');
1594 if (!is_dir($dir)) @mkdir($dir, 0775, true);
1595 return $dir . DIRECTORY_SEPARATOR . 'dbxError.log';
1596 }
1597
1599 public function error_type(int $errno): string {
1600 $types = array(
1601 E_ERROR => 'E_ERROR',
1602 E_WARNING => 'E_WARNING',
1603 E_PARSE => 'E_PARSE',
1604 E_NOTICE => 'E_NOTICE',
1605 E_CORE_ERROR => 'E_CORE_ERROR',
1606 E_CORE_WARNING => 'E_CORE_WARNING',
1607 E_COMPILE_ERROR => 'E_COMPILE_ERROR',
1608 E_COMPILE_WARNING => 'E_COMPILE_WARNING',
1609 E_USER_ERROR => 'E_USER_ERROR',
1610 E_USER_WARNING => 'E_USER_WARNING',
1611 E_USER_NOTICE => 'E_USER_NOTICE',
1612 E_STRICT => 'E_STRICT',
1613 E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
1614 E_DEPRECATED => 'E_DEPRECATED',
1615 E_USER_DEPRECATED => 'E_USER_DEPRECATED',
1616 );
1617 return $types[$errno] ?? 'E_UNKNOWN';
1618 }
1619
1621 public function write_php_error_log(string $type, string $message, string $file = '', int $line = 0): void {
1622 $request = $_SERVER['REQUEST_METHOD'] ?? 'CLI';
1623 $uri = $_SERVER['REQUEST_URI'] ?? '';
1624 $ip = $_SERVER['REMOTE_ADDR'] ?? '';
1625 $log = sprintf(
1626 "[%s] %s: %s in %s:%d | %s %s | IP=%s%s",
1627 date('Y-m-d H:i:s'),
1628 $type,
1629 str_replace(array("\r", "\n"), ' ', $message),
1630 $file,
1631 $line,
1632 $request,
1633 $uri,
1634 $ip,
1635 PHP_EOL
1636 );
1637 error_log($log, 3, $this->error_log_file());
1638 }
1639
1647 public function json_response(array $data, bool $withRuntime = false): void {
1648 if ($withRuntime) {
1649 $runtimeService = $this->get_system_obj('dbxRuntime');
1650 $runtime = number_format($runtimeService->current_php_runtime(), 3, '.', '');
1651 $data['dbx_php_runtime'] = $runtime;
1652 $data['_dbx_runtime'] = array('php' => $runtime);
1653 $runtimeService->send_headers();
1654 }
1655
1656 if (!headers_sent()) {
1657 header('Content-Type: application/json; charset=utf-8');
1658 }
1659
1660 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
1661 exit;
1662 }
1663
1678 public function timer($section,$info='') {
1679 global $dbx_run_timer;
1680
1681 $empty = array();
1682 $time = microtime(true);
1683 $memory = memory_get_peak_usage();
1684
1685
1686 if (!isset($dbx_run_timer[$section])) {
1687 //dbx_debug("#TIMER NEW SET");
1688 $dbx_run_timer[$section]['start_time'] =$time;
1689 $dbx_run_timer[$section]['end_time'] =-1;
1690 $dbx_run_timer[$section]['start_memory']=$memory;
1691 $dbx_run_timer[$section]['end_memory'] =-1;
1692 $dbx_run_timer[$section]['time'] =-1;
1693 $dbx_run_timer[$section]['memory'] =-1;
1694 $dbx_run_timer[$section]['info'] =$info;
1695 $this->timer_state[$section] = array(
1696 'running' => 1,
1697 'segment_start_time' => $time,
1698 'segment_start_memory' => $memory,
1699 'segments' => 0,
1700 );
1701 } else {
1702 $state = $this->timer_state[$section] ?? array();
1703 $running = (int) ($state['running'] ?? (($dbx_run_timer[$section]['end_time'] ?? -1) == -1 ? 1 : 0));
1704
1705 if ($running) {
1706 //dbx_debug("#TIMER ADD SET");
1707 $segment_start_time = (float) ($state['segment_start_time'] ?? $dbx_run_timer[$section]['start_time'] ?? $time);
1708 $segment_start_memory = (int) ($state['segment_start_memory'] ?? $dbx_run_timer[$section]['start_memory'] ?? $memory);
1709 $time_sum = max(0, (float) ($dbx_run_timer[$section]['time'] ?? 0));
1710 $memory_sum = max(0, (int) ($dbx_run_timer[$section]['memory'] ?? 0));
1711
1712 $dbx_run_timer[$section]['end_time'] = $time;
1713 $dbx_run_timer[$section]['end_memory']= $memory;
1714 $dbx_run_timer[$section]['time'] = $time_sum + max(0, $time - $segment_start_time);
1715 $dbx_run_timer[$section]['memory'] = $memory_sum + max(0, $memory - $segment_start_memory);
1716 $this->timer_state[$section] = array(
1717 'running' => 0,
1718 'segment_start_time' => $segment_start_time,
1719 'segment_start_memory' => $segment_start_memory,
1720 'segments' => (int) ($state['segments'] ?? 0) + 1,
1721 );
1722 } elseif ($info !== '') {
1723 if (($dbx_run_timer[$section]['info'] ?? '') === '') {
1724 $dbx_run_timer[$section]['info'] = $info;
1725 }
1726
1727 $dbx_run_timer[$section]['end_time'] = -1;
1728 $dbx_run_timer[$section]['end_memory'] = -1;
1729 $this->timer_state[$section] = array(
1730 'running' => 1,
1731 'segment_start_time' => $time,
1732 'segment_start_memory' => $memory,
1733 'segments' => (int) ($state['segments'] ?? 0),
1734 );
1735 }
1736 }
1737 //dbx_debug("#TIMER ($section)",$dbx_run_timer);
1738
1739 }
1740
1753 public function get_design_skin_ids(string $design = ''): array {
1754 static $cache = array();
1755
1756 $design = $this->resolve_skin_design($design);
1757 if (isset($cache[$design])) {
1758 return $cache[$design];
1759 }
1760
1761 $skins = array();
1762 $pattern = $this->get_base_dir() . 'dbx/design/' . $design . '/css/skin-*.css';
1763 foreach (glob($pattern) ?: array() as $file) {
1764 $name = pathinfo($file, PATHINFO_FILENAME);
1765 $skin = preg_replace('/^skin-/', '', (string)$name);
1766 if ($skin !== '' && preg_match('/^[a-z0-9][a-z0-9_-]*$/', $skin)) {
1767 $skins[$skin] = $skin;
1768 }
1769 }
1770
1771 $preferred = array_flip(array('hell', 'gelb', 'rot', 'gruen', 'blau', 'dunkel'));
1772 uasort($skins, static function (string $a, string $b) use ($preferred): int {
1773 $aRank = $preferred[$a] ?? 1000;
1774 $bRank = $preferred[$b] ?? 1000;
1775 return $aRank === $bRank ? strnatcasecmp($a, $b) : $aRank <=> $bRank;
1776 });
1777
1778 $cache[$design] = array_values($skins);
1779 return $cache[$design];
1780 }
1781
1786 private function resolve_skin_design(string $design = ''): string {
1787 $design = trim($design);
1788 if ($design === '') {
1789 $design = (string)$this->get_system_var(
1790 'dbx_activ_design',
1791 $this->get_system_var('dbx_design', 'dbxapp')
1792 );
1793 }
1794
1795 $key = strtolower($design);
1796 if ($key === 'user' || $key === 'admin') {
1797 $config = $this->get_config('dbx');
1798 $design = (string)($config[$key === 'admin' ? 'default_design_admin' : 'default_design_user'] ?? 'dbxapp');
1799 } elseif ($key === 'fleurop') {
1800 $design = 'flowers';
1801 }
1802
1803 return preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/', $design) ? $design : 'dbxapp';
1804 }
1805
1813 public function normalize_skin(string $skin = '', string $design = ''): string {
1814 $skin = strtolower(trim($skin));
1815 $skinIds = $this->get_design_skin_ids($design);
1816
1817 $map = array(
1818 'blue' => 'blau',
1819 'blau' => 'blau',
1820 'green' => 'gruen',
1821 'gruen' => 'gruen',
1822 'grün' => 'gruen',
1823 'red' => 'rot',
1824 'rot' => 'rot',
1825 'black' => 'dunkel',
1826 'dark' => 'dunkel',
1827 'dunkel' => 'dunkel',
1828 'yellow' => 'gelb',
1829 'gelb' => 'gelb',
1830 'light' => 'hell',
1831 'hell' => 'hell',
1832 'white' => 'hell',
1833 );
1834
1835 if ($skin !== '' && isset($map[$skin])) {
1836 $skin = $map[$skin];
1837 }
1838
1839 if ($skin === '' || !in_array($skin, $skinIds, true)) {
1840 $cfg = strtolower(trim((string) $this->get_config('dbx', 'default_color', 'blau')));
1841 $skin = $map[$cfg] ?? $cfg;
1842 }
1843
1844 if (!in_array($skin, $skinIds, true)) {
1845 $skin = in_array('blau', $skinIds, true)
1846 ? 'blau'
1847 : (in_array('hell', $skinIds, true) ? 'hell' : (string)($skinIds[0] ?? 'blau'));
1848 }
1849
1850 return $skin;
1851 }
1852
1858 public function get_skin(): string {
1859 return $this->normalize_skin((string) $this->get_system_var('dbx_color', ''));
1860 }
1861
1867 public function get_skin_css(): string {
1868 $design = $this->resolve_skin_design((string)$this->get_system_var(
1869 'dbx_activ_design',
1870 $this->get_system_var('dbx_design', 'dbxapp')
1871 ));
1872 $skin = $this->normalize_skin((string)$this->get_system_var('dbx_color', ''), $design);
1873
1874 return 'dbx/design/' . $design . '/css/skin-' . $skin . '.css';
1875 }
1876
1882 public function get_skin_class(): string {
1883 $skin = $this->get_skin();
1884 $cls = 'skin-' . $skin;
1885
1886 if ($skin === 'dunkel') {
1887 $cls .= ' theme-dark';
1888 }
1889
1890 return $cls;
1891 }
1892
1898 public function load_content_cache_classes(): void {
1899 static $loaded = false;
1900 if ($loaded) {
1901 return;
1902 }
1903
1904 require_once $this->os_path($this->get_base_dir() . 'dbx/modules/dbxContent/include/dbxContent_bootstrap_sync.php');
1905 $loaded = true;
1906 }
1907
1913 public function get_content_permalink_mode(): string {
1914 $file = $this->os_path($this->get_base_dir() . 'dbx/modules/dbxContent/include/dbxContentLng.class.php');
1915 if (is_file($file)) {
1916 require_once $file;
1917 }
1918
1919 return class_exists('\dbx\dbxContent\dbxContentLng')
1921 : 'content';
1922 }
1923
1930 public function log_missing($missing = '') {
1931 $missing = trim((string)$missing);
1932 if ($missing === '') {
1933 return 0;
1934 }
1935
1936 if (strlen($missing) > 250) {
1937 $missing = substr($missing, 0, 250);
1938 }
1939
1940 $transactionStarted = false;
1941
1942 try {
1943 $db = $this->get_system_obj('dbxDB');
1944 if (!is_object($db)) {
1945 return 0;
1946 }
1947
1948 if ((int)$db->begin('dbxMissing') !== 1) {
1949 throw new \RuntimeException('dbxMissing-Transaktion konnte nicht gestartet werden.');
1950 }
1951 $transactionStarted = true;
1952
1953 $uid = (int)$this->user();
1954 $rec = $db->select1('dbxMissing', array('missing' => $missing), 'id,count', 0);
1955 $request = $this->missing_request_source();
1956
1957 if (is_array($rec) && (int)($rec['id'] ?? 0) > 0) {
1958 $id = (int)$rec['id'];
1959 $values = array(
1960 'count' => ((int)($rec['count'] ?? 0)) + 1,
1961 );
1962 if ($request !== '') {
1963 $values['request'] = $request;
1964 }
1965
1966 if ((int)$db->update('dbxMissing', $values, $id, 0, 1, 1, 0) !== 1) {
1967 throw new \RuntimeException('dbxMissing-Zaehler konnte nicht aktualisiert werden.');
1968 }
1969 if ((int)$db->commit('dbxMissing') !== 1) {
1970 throw new \RuntimeException('dbxMissing-Transaktion konnte nicht abgeschlossen werden.');
1971 }
1972 $transactionStarted = false;
1973 return $id;
1974 }
1975
1976 $values = array(
1977 'missing' => $missing,
1978 'count' => 1,
1979 'owner' => $uid,
1980 );
1981 if ($request !== '') {
1982 $values['request'] = $request;
1983 }
1984
1985 $ok = $db->insert('dbxMissing', $values, 0, 1, 1, 0);
1986 $id = $ok ? (int)$db->get_insert_id() : 0;
1987 if ($id <= 0) {
1988 throw new \RuntimeException('dbxMissing-Eintrag konnte nicht gespeichert werden.');
1989 }
1990 if ((int)$db->commit('dbxMissing') !== 1) {
1991 throw new \RuntimeException('dbxMissing-Transaktion konnte nicht abgeschlossen werden.');
1992 }
1993 $transactionStarted = false;
1994
1995 return $id;
1996 } catch (\Throwable $e) {
1997 if ($transactionStarted && isset($db) && is_object($db)) {
1998 $db->rollback('dbxMissing');
1999 }
2000 $this->write_php_error_log(get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
2001 }
2002
2003 return 0;
2004 }
2005
2007 private function missing_request_source(): string {
2008 $referer = trim((string)($_SERVER['HTTP_REFERER'] ?? ''));
2009 if ($referer === '') {
2010 return '';
2011 }
2012
2013 $parts = parse_url($referer);
2014 if (!is_array($parts)) {
2015 return '';
2016 }
2017
2018 $source = '';
2019 if (!empty($parts['host'])) {
2020 $source .= (!empty($parts['scheme']) ? strtolower((string)$parts['scheme']) : 'https') . '://';
2021 $source .= strtolower((string)$parts['host']);
2022 if (!empty($parts['port'])) {
2023 $source .= ':' . (int)$parts['port'];
2024 }
2025 }
2026 $source .= (string)($parts['path'] ?? '');
2027 $source = trim($source);
2028
2029 return strlen($source) > 250 ? substr($source, 0, 250) : $source;
2030 }
2031
2047 public function sys_msg($status = '', $about = '', $rid = '', $why = '', $what = '') {
2048 // Automatisierte Tests dürfen niemals die reale Systemmeldungsdatenbank
2049 // verändern. Einzelne, ausdrücklich darauf ausgelegte Isolationstests
2050 // können das Schreiben über DBX_SELFTEST_ALLOW_SYSMSG=1 freigeben.
2051 if ((string)getenv('DBX_SELFTEST') === '1'
2052 && (string)getenv('DBX_SELFTEST_ALLOW_SYSMSG') !== '1') {
2053 return 0;
2054 }
2055
2056 if ($this->sys_msg_running) {
2057 return 0;
2058 }
2059
2060 $this->sys_msg_running = true;
2061
2062 try {
2063 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
2064 $caller = $trace[1] ?? null;
2065 $file = $caller['file'] ?? '';
2066 $line = (int)($caller['line'] ?? 0);
2067
2068 $status = strtolower(trim((string)$status));
2069 if ($status === '') {
2070 $status = 'info';
2071 }
2072
2073 $level_map = array(
2074 'debug' => 5,
2075 'info' => 10,
2076 'login' => 15,
2077 'notice' => 15,
2078 'warning' => 20,
2079 'warn' => 20,
2080 'security' => 30,
2081 'error' => 40,
2082 'fatal' => 50,
2083 );
2084
2085 $level = $level_map[$status] ?? 10;
2086 if ($status === 'warn') {
2087 $status = 'warning';
2088 }
2089
2090 $sysMsgLevel = strtolower(trim((string) $this->get_config('dbx', 'sys_msg_level', 'all')));
2091 if ($sysMsgLevel === '') {
2092 $sysMsgLevel = 'all';
2093 }
2094
2095 $minLevel = 0;
2096 if ($sysMsgLevel === 'error') {
2097 $minLevel = 40;
2098 } elseif ($sysMsgLevel === 'warning' || $sysMsgLevel === 'warn') {
2099 $minLevel = 20;
2100 }
2101
2102 if ($level < $minLevel) {
2103 return 0;
2104 }
2105
2106 $modul = $this->get_modul_var('dbx_modul', $this->get_system_var('dbx_activ_modul' , 'dbx', '*'), rules: '*');
2107 $action = $this->get_modul_var('dbx_run1' , $this->get_system_var('dbx_activ_action', '' , '*'), rules: '*');
2108 $work = $this->get_modul_var('dbx_run2' , '', '*');
2109
2110 $data_json = '';
2111 if (is_array($what) || is_object($what)) {
2112 $data_json = json_encode($what, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
2113 $what_text = $data_json ?: '';
2114 } else {
2115 $what_text = (string)$what;
2116 }
2117
2118 $message_parts = array();
2119 if ((string)$about !== '') $message_parts[] = (string)$about;
2120 if ((string)$why !== '') $message_parts[] = 'why=' . (string)$why;
2121 if ($what_text !== '') $message_parts[] = 'what=' . $what_text;
2122 if ((string)$rid !== '') $message_parts[] = 'rid=' . (string)$rid;
2123 $message = implode(' | ', $message_parts);
2124
2125 $record = array(
2126 'xuser' => $this->user('id'),
2127 'level' => $level,
2128 'status' => $status,
2129 'about' => (string)$about,
2130 'rid' => (string)$rid,
2131 'why' => (string)$why,
2132 'what' => $what_text,
2133 'message' => $message,
2134 'modul' => (string)$modul,
2135 'action' => (string)$action,
2136 'work' => (string)$work,
2137 'source_file' => (string)$file,
2138 'source_line' => $line,
2139 'data_json' => $data_json,
2140 );
2141
2142 $oDB = $this->get_system_obj('dbxDB');
2143 $prevReport = (int)$oDB->_report_error;
2144 $oDB->_report_error = 0;
2145 $ok = $oDB->insert('dbxSysMsg', $record, 0, 1, 0, 0);
2146 $oDB->_report_error = $prevReport;
2147 $insertId = $ok ? $oDB->get_insert_id() : 0;
2148
2149 dbx()->debug("##SYS-MSG### ok=($ok) id=($insertId) Level=($level) Status=($status) Modul=($modul) Action=($action) Work=($work) About=($about) RID=($rid) Why=($why) What=($what_text)");
2150
2151 return (int)$insertId;
2152 } finally {
2153 $this->sys_msg_running = false;
2154 }
2155 }
2156
2168 public function norep($norep,$i=0) {
2169 $norep=str_replace("\r",'',$norep);
2170 $norep_id='norep_'.$this->next_id();
2171 $_SESSION['dbx']['norep'][$norep_id]=$norep;
2172 return '['.$norep_id.']';
2173 }
2174
2181 public function next_id(int $add = 1): int {
2182 // Aktuellen Zählerwert aus der "Remember"-Datenstruktur abrufen
2183 $i = $this->get_remember_var('dbx_next_i', 0, 'dbx');
2184
2185 // Zähler um den angegebenen Wert erhöhen
2186 $i += $add;
2187
2188 // Aktualisierten Zählerwert in die "Remember"-Datenstruktur speichern
2189 $this->set_remember_var('dbx_next_i', $i, 'dbx');
2190
2191 // Neuen Zählerwert zurückgeben
2192 return $i;
2193 }
2194
2201 public function is_modul($modul) {
2202 $retval=false;
2203 if ($modul) {
2204 $modul_class_file=$this->get_base_dir()."dbx/modules/$modul/".$modul.".class.php";
2205 if (file_exists($modul_class_file)) $retval=true;
2206 }
2207 return $retval;
2208 }
2209
2217 public function is_design($design,$page='default') {
2218 $admin=$this->can('admin');
2219 $firstchar=substr($design,0,1);
2220 if (!$admin && $firstchar == '_') return false;
2221 if (!$admin && $firstchar == '-') return false;
2222
2223 $design_tpl=$this->get_base_dir()."dbx/design/$design/htm/$page.htm";
2224 if (file_exists($design_tpl)) return true;
2225 if ($page != 'default') {
2226 $design_tpl=$this->get_base_dir()."dbx/design/$design/htm/default.htm";
2227 if (file_exists($design_tpl)) return true;
2228 }
2229
2230 return false;
2231 }
2232
2240 public function redirect($redirect, $timer = 0) {
2241 $timer = ($timer * 1000);
2242 $base = $this->get_base_url();
2243 $ajax = $this->get_system_var('dbx_ajax', 0, 'int');
2244
2245 dbx()->debug("run redirect ($redirect)");
2246
2247 if (!str_contains($redirect, '://'))
2248 $redir = $base . $redirect;
2249 else
2250 $redir = $redirect;
2251
2252 dbx()->debug("#dbx_redirect Call=($redirect) redir=($redir) Ajax=($ajax) timer=($timer)");
2253
2254 $redir_js = json_encode($redir);
2255 $allow_internal = "if(window.dbx&&dbx.utilities&&dbx.utilities.leaveGuard)"
2256 . "{dbx.utilities.leaveGuard.allowIfInternal($redir_js);}";
2257
2258 if (!$timer) {
2259 $script = "<script>$allow_internal window.location.replace($redir_js);</script>";
2260 } else {
2261 $script = "<script>setTimeout(function() { $allow_internal window.location.replace($redir_js); }, $timer);</script>";
2262 }
2263
2264 return $script;
2265 }
2266
2275 public function set_cookie_var($cookie,$key,$val) {
2276 $_SESSION['dbx']['cookie'][$cookie][$key]=$val;
2277 }
2278
2286 public function has_text($string,$find) {
2287 return strpos('~'.$string,$find);
2288 }
2289
2296 public function html($html) {
2297 return htmlentities($html, ENT_QUOTES);
2298 }
2299
2310 public function esc($value): string {
2311 return htmlspecialchars(
2312 (string)$value,
2313 ENT_QUOTES | ENT_SUBSTITUTE,
2314 'UTF-8'
2315 );
2316 }
2317
2326 public function search_defaults(array $overrides = array()): array {
2327 $defaults = array(
2328 'name' => '',
2329 'value' => '',
2330 'placeholder' => '🔍',
2331 'title' => 'Suchen',
2332 'tooltip' => '',
2333 'errormsg' => '',
2334 'class' => '',
2335 'input_class' => 'form-control-sm dbx-grid-search',
2336 'data_role' => 'search',
2337 'wrap_class' => '',
2338 'wrap_style' => '',
2339 'label' => '',
2340 'style' => '',
2341 'extra_attrs' => '',
2342 'i' => 0,
2343 );
2344
2345 if (array_key_exists('placeholder', $overrides) && trim((string) $overrides['placeholder']) === '') {
2346 unset($overrides['placeholder']);
2347 }
2348
2349 $data = array_merge($defaults, $overrides);
2350 if (trim((string)$data['tooltip']) === '') {
2351 $data['tooltip'] = (string)$data['title'];
2352 }
2353 return $data;
2354 }
2355
2362 public function timestamp($add_sec=0) {
2363 list($usec, $sec) = explode(" ",microtime());
2364 $time= ((float) $usec + (float)$sec);
2365 $time= (float) ($time + ($add_sec));
2366 return $time;
2367 }
2368
2376 public function time_diff($starttime=0,$endtime=0) {
2377 if (!$starttime) $starttime=$this->timestamp();
2378 if (!$endtime) $endtime =$this->timestamp();
2379 return ($endtime-$starttime);
2380 }
2381
2390 public function part_select($vor,$nach,$part) {
2391 $leng= strlen($vor);
2392 $pos1= strpos($part, $vor);
2393
2394 if ($pos1 === false) {
2395 return '';
2396 }
2397
2398 $part= substr($part, ($pos1+$leng));
2399 $pos2= strpos($part, $nach);
2400
2401 if ($pos2 === false) {
2402 return '';
2403 }
2404
2405 $part= substr($part, 0,$pos2);
2406
2407 return $part;
2408 }
2409
2416 public function parse_url($data) {
2417 if (!is_array($data)) {
2418 $first=substr($data,0,1);
2419 if ($data && $first != '=') {
2420 if (strpos($data,'=')) {
2421 parse_str($data,$xdata);
2422 $data=$xdata;
2423 }
2424 }
2425 }
2426 return $data;
2427 }
2428
2435 public function is_int_value($value) {
2436 if (is_int($value)) return 1;
2437 if (is_string($value) && filter_var($value, FILTER_VALIDATE_INT) !== false) return 1;
2438 return 0;
2439 }
2440
2448 public function new_password($minlength, $special = '-_!') {
2449 $length = (int)$minlength;
2450 $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' . (string)$special;
2451 if ($length < 1 || $alphabet === '') {
2452 return '';
2453 }
2454
2455 $password = '';
2456 $lastIndex = strlen($alphabet) - 1;
2457 for ($i = 0; $i < $length; $i++) {
2458 $password .= $alphabet[random_int(0, $lastIndex)];
2459 }
2460
2461 return $password;
2462 }
2463
2465 private function emit_http_response_body(string $response): void {
2466 if (strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'HEAD') {
2467 echo $response;
2468 }
2469 }
2470
2472 private function serve_full_page_cache_hit(string $html): void {
2473 $session = $this->get_system_obj('dbxSession');
2474 $discardedEphemeralSession = is_object($session)
2475 && method_exists($session, 'discard_ephemeral_anonymous_session')
2476 && $session->discard_ephemeral_anonymous_session(true);
2477 if (!$discardedEphemeralSession && session_status() === PHP_SESSION_ACTIVE) {
2478 // check_remember()/check_lng() liefen bereits vor dem Cache-Lesen.
2479 // session_abort() wuerde eine gerade ausgewaehlte Sprache, Design oder
2480 // Farbe nur bei Cache-HITs wieder verwerfen. PHP-Session daher sauber
2481 // persistieren; ein Render- oder Content-DB-Lauf bleibt trotzdem aus.
2482 session_write_close();
2483 }
2484
2485 if (!headers_sent()) {
2486 // Der PageCache ist ausschliesslich fuer unpersonalisierte Gastseiten
2487 // aktiv. Die PHP-Session darf diese fertige Antwort daher weder mit
2488 // Set-Cookie noch mit privaten/no-cache Headern entwerten.
2489 header_remove('Set-Cookie');
2490 header_remove('Expires');
2491 header_remove('Pragma');
2492 $ttl = max(0, min(3600, (int)$this->get_config('dbx', 'full_page_browser_ttl', 60)));
2493 header('Cache-Control: public, max-age=' . $ttl . ', stale-while-revalidate=30');
2494 $etag = '"' . hash('sha256', $html) . '"';
2495 header('ETag: ' . $etag);
2496 $ifNoneMatch = trim((string)($_SERVER['HTTP_IF_NONE_MATCH'] ?? ''));
2497 if ($ifNoneMatch !== '' && hash_equals($etag, $ifNoneMatch)) {
2498 http_response_code(304);
2499 $this->get_system_obj('dbxRuntime')->send_headers();
2500 exit;
2501 }
2502 }
2503
2504 $this->get_system_obj('dbxRuntime')->send_headers();
2505 $this->emit_http_response_body($html);
2506 exit;
2507 }
2508
2510 private function render_web_app(): string {
2511 $sessionId = session_id();
2512 $pageContent = '';
2513 $this->debug("#### Session #### PHP-ID=($sessionId)");
2514
2515 $this->timer('system', 'full-app');
2516 $this->timer('system-load', 'load Kernel');
2517
2518 $webApp = $this->get_system_obj('dbxWebApp');
2519 $session = $this->get_system_obj('dbxSession');
2520 $interpreter = null;
2521 $this->timer('system-load');
2522
2523 $this->timer('session-load', 'Session load');
2524 $session->load_session();
2525 $this->timer('session-load');
2526
2527 $this->timer('system-check', 'System check');
2528 $this->set_system_var('dbx_activ_modul', 'dbx');
2529 $webApp->check_request();
2530 $webApp->check_remember();
2531 // Der Installationsschalter muss vor Permalink-, Datenbank- und
2532 // Seiten-Cache-Zugriffen bekannt sein. Eine frische Auslieferung besitzt
2533 // zu diesem Zeitpunkt noch keine provisionierten DD-Tabellen.
2534 $webApp->check_config();
2535 $webApp->check_lng();
2536 $sync = $this->get_request_var('dbx_sync', 1, 'int');
2537 $installMode = (int)$this->get_system_var('dbx_install', 0, 'int') === 1;
2538
2539 if (!$installMode) {
2540 if ($webApp->apply_canonical_home_redirect()) {
2541 $this->timer('system-check');
2542 $this->timer('system');
2543 return '';
2544 }
2545 if ($webApp->apply_content_permalink_redirect()) {
2546 $this->timer('system-check');
2547 $this->timer('system');
2548 return '';
2549 }
2550
2551 // Fehlende statische Dateien muessen vor dem Seiten-Cache erkannt
2552 // werden. Normale Permalinks bleiben davon unberuehrt.
2553 if ($webApp->check_missing()) {
2554 exit;
2555 }
2556
2558 if (\dbx\dbxContent\dbxContentPageCache::prepareFullPageRequest()) {
2560 if ($cachedPage !== null) {
2561 $this->serve_full_page_cache_hit($cachedPage);
2562 }
2563 }
2564 $webApp->check_perma();
2566 } else {
2567 // Ein beliebiger angeforderter Permalink darf den Installer nicht
2568 // in Content-Auflösung oder eine 404-Darstellung lenken.
2569 $this->set_system_var('dbx_permalink', '');
2570 }
2571
2572 $webApp->check_design();
2573 $webApp->check_modul();
2574
2575 $self = $this->get_self_url();
2576 $base = $this->get_base_url();
2577 $uid = $this->user();
2578 $ajax = $this->get_system_var('dbx_ajax', 0, 'int');
2579 $cache = $this->get_config('dbx', 'cache');
2580 $perma = $this->get_system_var('dbx_permalink', 'undef');
2581 $modul = $this->get_system_var('dbx_modul', 'undef');
2582 $this->debug("#DBX RUN Base-URL($base) Self=($self) Ajax=($ajax) Perma ($perma) User=($uid) SYS CACHE=($cache) ");
2583 $this->timer('system-check');
2584
2585 $this->timer($modul, 'Master-Modul');
2586 $moduleContent = $webApp->run();
2587 $this->timer($modul);
2588
2589 $this->timer('page-load', 'Page-Load');
2590 $this->debug("#RUN-DBXWEBAPP SYNC=$sync");
2591 if ($sync) {
2592 $pageContent = $webApp->design_load($moduleContent);
2593 if ($interpreter === null) {
2594 $interpreter = $this->get_system_obj('dbxInterpreter');
2595 }
2596 $this->timer('interpreter', 'Interpreter');
2597 $pageContent = $interpreter->run($pageContent);
2598 $this->timer('interpreter');
2599 $pageContent = $webApp->add_norep($pageContent);
2600 $pageContent = $webApp->add_editor_files_data($pageContent);
2601 $pageContent = $webApp->out_filter($pageContent);
2602 } else {
2603 $this->debug('no sync no output');
2604 http_response_code(204);
2605 }
2606 $this->timer('page-load');
2607 $this->timer('system');
2608 return (string)$pageContent;
2609 }
2610
2612 public function run_web_app_request(): void {
2613 $response = $this->render_web_app();
2614 $syncRequest = (int)$this->get_request_var('dbx_sync', 1, 'int') === 1;
2615
2616 if ($syncRequest
2617 && class_exists('\\dbx\\dbxContent\\dbxContentPageCache', false)
2618 && \dbx\dbxContent\dbxContentPageCache::isPreparedFullPageRequest()) {
2620 $this->debug($stored
2621 ? '#FULL-PAGE-CACHE stored exact final guest response'
2622 : '#FULL-PAGE-CACHE final response not stored');
2623 }
2624
2625 $session = $this->get_system_obj('dbxSession');
2626 $this->debug("call session_save($syncRequest)");
2627 $discardedEphemeralSession = method_exists($session, 'discard_ephemeral_anonymous_session')
2628 && $session->discard_ephemeral_anonymous_session(false);
2629 if (!$discardedEphemeralSession) {
2630 $session->save_session();
2631 $session->clean_session();
2632 if (!empty($GLOBALS['dbx_session_destroy_pending'])) {
2633 $session->destroy_php_session();
2634 }
2635 }
2636
2637 if ($syncRequest) {
2638 $this->get_system_obj('dbxRuntime')->send_headers();
2639 }
2640 // HEAD liefert dieselben Header wie GET, aber gemaess HTTP keinen Body.
2641 // Das gilt auch fuer einen Cache-MISS, der oben vollstaendig gerendert
2642 // werden darf, um den Cache fuer den folgenden GET vorzubereiten.
2643 $this->emit_http_response_body($response);
2644
2645 while (ob_get_level() > 0) {
2646 if (!@ob_end_flush()) break;
2647 }
2648
2649 $runtimeService = $this->get_system_obj('dbxRuntime');
2650 $runtimeService->debug_timer(0);
2651 if ($syncRequest && (int)$this->get_system_var('dbx_ajax', 0, 'int') !== 1) {
2652 $runtimeService->store_performance_timer();
2653 }
2654 $this->debug('#END#');
2655 }
2656
2663 public function debug2($line) {
2664 $file = $this->get_file_dir() . "dbxDebug2.txt";
2665 $file = $this->os_path($file);
2666 file_put_contents($file, $line, FILE_APPEND);
2667 }
2668
2686 public function debug($txt, $data1 = '', $data2 = '', $data3 = '') {
2687 $activ = $this->get_remember_var('dbx_debug_activ', -1, 'dbx');
2688 if ($activ == -1) {
2689 $activ = 0;
2690 $debugActiv = $this->get_file_dir() . "dbxDebugActiv.txt";
2691 $debugActiv = $this->os_path($debugActiv);
2692 if (file_exists($debugActiv)) {
2693 $activ = 1;
2694 }
2695 $this->set_remember_var('dbx_debug_activ', $activ, 'dbx');
2696 }
2697
2698 if (!$activ) {
2699 return;
2700 }
2701
2702 $vars = '';
2703 $file = $this->get_file_dir() . "dbxDebug.txt";
2704 $file = $this->os_path($file);
2705
2706 foreach (array($data1, $data2, $data3) as $data) {
2707 if (is_array($data)) {
2708 $vars .= print_r($data, true);
2709 } else {
2710 if ($data > '') {
2711 $vars .= $data . "\n";
2712 }
2713 }
2714 }
2715
2716 $txt .= "\n" . $vars . "\n";
2717 file_put_contents($file, $txt, FILE_APPEND);
2718 }
2719
2728 private function get_SysClassOverrideName(string $class): string {
2729 if (str_starts_with($class, 'dbx')) {
2730 $suffix = substr($class, 3);
2731 return 'my' . ($suffix ?: $class);
2732 }
2733 return 'my' . $class;
2734 }
2735
2748 private function ensure_SysClassOverride(string $class, string $myClass, string $baseClass): string {
2749 if ($baseClass === "\\dbxUndefClass" || !class_exists($baseClass, false)) {
2750 return '';
2751 }
2752
2753 $moduleDir = $this->os_path($this->get_base_dir() . 'dbx/modules/myX/');
2754 $sysDir = $this->os_path($moduleDir . 'sysclass/');
2755 $file = $this->os_path($sysDir . $myClass . '.class.php');
2756
2757 if (!is_dir($sysDir)) {
2758 mkdir($sysDir, 0777, true);
2759 }
2760
2761 $cfgDir = $this->os_path($moduleDir . 'cfg/');
2762 if (!is_dir($cfgDir)) {
2763 mkdir($cfgDir, 0777, true);
2764 }
2765
2766 $cfgFile = $this->os_path($cfgDir . 'config.php');
2767 if (!file_exists($cfgFile)) {
2768 file_put_contents($cfgFile, "<?php\n\$config['version']='1';\n\$config['activ']='1';\n\$config['groups']='*';\n");
2769 }
2770
2771 $moduleFile = $this->os_path($moduleDir . 'myX.class.php');
2772 if (!file_exists($moduleFile)) {
2773 file_put_contents($moduleFile, "<?php\nnamespace dbx\\myX;\n\nclass myX {\n public function run() {\n return 'myX system module';\n }\n}\n");
2774 }
2775
2776 if (!file_exists($file)) {
2777 $content = "<?php\n";
2778 $content .= "/**\n";
2779 $content .= " * Auto-generated DBX system class override.\n";
2780 $content .= " * Requested class: $class\n";
2781 $content .= " * Override class: $myClass\n";
2782 $content .= " */\n";
2783 $content .= "class $myClass extends $class {\n";
2784 $content .= "}\n";
2785 file_put_contents($file, $content);
2786 }
2787
2788 return $file;
2789 }
2790}
2791
2805function dbx(): dbxApi {
2806 static $api = null;
2807 if ($api === null) {
2808 $api = new dbxApi();
2809 }
2810 return $api;
2811}
2812
2813
2819function ge_stichtag() {
2820 $heute = new DateTime();
2821 $grenze = new DateTime('2025-06-01');
2822 return $heute >= $grenze;
2823}
2824
2825
2833function dbx_copy_recursive($src, $dst) {
2834 $src = rtrim($src, '/\\');
2835 $dst = rtrim($dst, '/\\');
2836
2837 if (!is_dir($src)) {
2838 dbx()->debug("dbx_copy_recursive Error DIR");
2839 return 0;
2840 }
2841
2842 if (!file_exists($dst)) {
2843 if (!mkdir($dst, 0777, true)) {
2844 dbx()->debug("dbx_copy_recursive mkdir Error($dst)");
2845 return 0;
2846 }
2847 }
2848
2849 $items = scandir($src);
2850 foreach ($items as $item) {
2851 if ($item === '.' || $item === '..') {
2852 continue;
2853 }
2854
2855 $srcPath = $src . DIRECTORY_SEPARATOR . $item;
2856 $dstPath = $dst . DIRECTORY_SEPARATOR . $item;
2857
2858 if (is_dir($srcPath)) {
2859 // Rekursiv für Verzeichnisse
2860 if (!dbx_copy_recursive($srcPath, $dstPath)) {
2861 dbx()->debug("dbx_copy_recursive Error A");
2862 return 0;
2863 }
2864 } else {
2865 // Datei kopieren (überschreiben erlaubt)
2866 if (!copy($srcPath, $dstPath)) {
2867 dbx()->debug("dbx_copy_recursive Error B");
2868
2869 return 0;
2870 }
2871 }
2872 }
2873
2874 return 1;
2875}
2876
2877
2878
2879
2894function dbx_DateTime($date_time='now',$calc=0,$special='') {
2895 $timezone = 'Europe/Berlin';
2896 $offset = 0; // Offset Sommer/Winter
2897
2898 if ($date_time=='now') {
2899 $offset = (60*60*$offset);
2900 $calc=($calc + $offset);
2901 $date_time = date("Y-m-d H:i:s", (time() + $calc));
2902 } else {
2903 $offset = (60*60*$offset);
2904 $calc=($calc + $offset);
2905 $date_time = date("Y-m-d H:i:s", (strtotime($date_time) + $calc ));
2906 }
2907
2908 if ($special) {
2909 $time=strtotime($date_time);
2910 $date_time=date("Y-m-d H:i:s", strtotime($special, $time));
2911 }
2912
2913
2914 $week_start = strtotime('last Sunday', time());
2915 $week_end = strtotime('next Sunday', time());
2916
2917 $month_start = strtotime('first day of this month', time());
2918 $month_end = strtotime('last day of this month', time());
2919
2920 $year_start = strtotime('first day of January', time());
2921 $year_end = strtotime('last day of December', time());
2922
2923 //$now_date = gmdate("Y-m-d H:i:s", (time() + $calc));
2924 return $date_time;
2925}
2926
2927
2941function dbx_make_dir(string $path): int {
2942 // Prüfen, ob das Verzeichnis bereits existiert
2943 if (is_dir($path)) return 1;
2944
2945 // Versuchen, das Verzeichnis rekursiv zu erstellen
2946 if (mkdir($path, 0777, true)) {
2947 return 1; // Erfolgreich erstellt
2948 }
2949
2950 return 0; // Fehler beim Erstellen
2951}
2952
2953
2967function dbx_sendMail($from,$fromname,$to,$subject,$text,$type='html',$attach='',$archiv=0) {
2968 $from = array('email' => $from, 'name' => $fromname);
2969 return dbx()->send_mail($from, $to, (string) $subject, (string) $text, (string) $type, $attach);
2970}
2971
2972
2982 $retval=false;
2983 $page_tpl=dbx()->get_base_dir()."dbx/tpl/htm/$page.htm";
2984 if (file_exists($page_tpl)) $retval=true;
2985 return $retval;
2986}
2987
2988
2989
2990
2991
2992
2993
2994
3038function dbx_lng_current(): string {
3039 $lng = strtolower(trim((string) dbx()->get_system_var('dbx_lng', 'de')));
3040 return $lng !== '' ? $lng : 'de';
3041}
3042
3048function dbx_accessible_lngs(): array {
3049 $raw = dbx()->get_config('dbx', 'accessible_lng', 'de');
3050 if ($raw === 'undef' || $raw === '' || $raw === null) {
3051 $raw = 'de';
3052 }
3053 if (is_array($raw)) {
3054 $out = array();
3055 foreach ($raw as $val) {
3056 $val = strtolower(trim((string) $val));
3057 if ($val !== '' && $val !== 'undef' && preg_match('/^[a-z]{2,3}$/', $val)) {
3058 $out[] = $val;
3059 }
3060 }
3061 return count($out) ? $out : array('de');
3062 }
3063
3064 $parts = preg_split('/\s*,\s*/', (string) $raw, -1, PREG_SPLIT_NO_EMPTY);
3065 $out = array();
3066 if (is_array($parts)) {
3067 foreach ($parts as $val) {
3068 $val = strtolower(trim((string) $val));
3069 if ($val !== '' && $val !== 'undef' && preg_match('/^[a-z]{2,3}$/', $val)) {
3070 $out[] = $val;
3071 }
3072 }
3073 }
3074
3075 return count($out) ? $out : array('de');
3076}
3077
3085function dbx_lng_name(string $base, string $lng = ''): string {
3086 $base = trim($base);
3087 if ($base === '') {
3088 return '';
3089 }
3090
3091 $lng = strtolower(trim($lng !== '' ? $lng : dbx_lng_current()));
3092 if ($lng === '') {
3093 return $base;
3094 }
3095
3096 return $base . '_' . $lng;
3097}
3098
3109function dbx_lng_resolve_file(string $dir, string $name, string $ext, string $lng = '', bool $fallback = true): string {
3110 $dir = str_replace('\\', '/', $dir);
3111 if ($dir !== '' && substr($dir, -1) !== '/') {
3112 $dir .= '/';
3113 }
3114
3115 $name = strtolower(trim($name));
3116 $ext = ltrim(strtolower(trim($ext)), '.');
3117 if ($name === '' || $ext === '') {
3118 return '';
3119 }
3120
3121 $lng = strtolower(trim($lng !== '' ? $lng : dbx_lng_current()));
3122 if ($lng !== '') {
3123 $pathLng = $dir . $name . '_' . $lng . '.' . $ext;
3124 if (is_file($pathLng)) {
3125 return dbx()->os_path($pathLng);
3126 }
3127 }
3128
3129 if (!$fallback) {
3130 return '';
3131 }
3132
3133 $pathDef = $dir . $name . '.' . $ext;
3134 if (is_file($pathDef)) {
3135 return dbx()->os_path($pathDef);
3136 }
3137
3138 return '';
3139}
3140
3154function dbx_modul_translate($content,$modul='',$lng='') {
3155 if (!$modul) $modul=dbx()->get_system_var('dbx_activ_modul','dbx');
3156 if (!$lng) $lng=dbx()->get_system_var('dbx_lng','de');
3157 $dir_file=dbx()->get_base_dir()."dbx/modules/$modul/translate.php";
3158 $dir_file=dbx()->os_path($dir_file);
3159 if (file_exists($dir_file)) {
3160 include $dir_file;
3161 }
3162 return $content;
3163}
3164
3173function dbx_replace_first($search_str, $replacement_str, $src_str){
3174 return (false !== ($pos = strpos($src_str, $search_str))) ? substr_replace($src_str, $replacement_str, $pos, strlen($search_str)) : $src_str;
3175}
3176
3177
3190function dbx_convertArrayToPHPCode(array $array, string $prefix): string {
3191 $code = "";
3192
3193 foreach ($array as $key => $value) {
3194 // Generiere den Schlüssel (numerisch oder als String)
3195 $keyPart = is_numeric($key) ? "[$key]" : "['" . addslashes($key) . "']";
3196
3197 if (is_array($value)) {
3198 // Rekursive Verarbeitung für verschachtelte Arrays
3199 $code .= dbx_convertArrayToPHPCode($value, $prefix . $keyPart);
3200 } else {
3201 // Wert formatieren
3202 if (is_string($value)) {
3203 // Strings escapen (inklusive Backslashes)
3204 $formattedValue = "'" . addslashes($value) . "'";
3205 } elseif (is_bool($value)) {
3206 // Booleans in `true` oder `false` konvertieren
3207 $formattedValue = $value ? 'true' : 'false';
3208 } elseif ($value === null) {
3209 // `null` als Wert setzen
3210 $formattedValue = 'null';
3211 } else {
3212 // Andere Datentypen (z. B. Zahlen) direkt verwenden
3213 $formattedValue = $value;
3214 }
3215
3216 // PHP-Code-Zuweisung generieren
3217 $code .= "$prefix$keyPart = $formattedValue;\n";
3218 }
3219 }
3220
3221 return $code;
3222}
3223
3224
3267function dbx_convert_charset(string $in, string $charset, string $incharset = 'UTF-8'): string {
3268 // Nur konvertieren, wenn Zielkodierung von Eingabekodierung abweicht
3269 if ($charset !== $incharset) {
3270 // Spezielle Behandlung für deutsche Umlaute und scharfes S
3271 $umlaute = [
3272 'ä' => chr(228), 'ö' => chr(246), 'ü' => chr(252), 'ß' => chr(223),
3273 'Ä' => chr(196), 'Ö' => chr(214), 'Ü' => chr(220)
3274 ];
3275 $in = str_replace(array_keys($umlaute), array_values($umlaute), $in);
3276
3277 // Kodierung mit automatischer Erkennung der Eingabekodierung konvertieren
3278 $in = mb_convert_encoding(
3279 $in,
3280 $charset,
3281 mb_detect_encoding($in, "UTF-8, $charset, ISO-8859-1, ISO-8859-15", true)
3282 );
3283 }
3284
3285 return $in;
3286}
3287
3288
3302function dbx_add_modul(string $modul, string $action, string $work = ''): string {
3303 // Grundstruktur mit Modul und Aktion aufbauen
3304 $content = '[modul=' . $modul . ']dbx_run1=' . $action;
3305
3306 // Falls 'work' definiert ist, hinzufügen
3307 if (!empty($work)) {
3308 $content .= '&dbx_run2=' . $work;
3309 }
3310
3311 // Abschluss des Modul-Strings
3312 $content .= '[/modul]';
3313 return $content;
3314}
3315
3316
3317
3331function dbx_validate_var($danger_value, $rules = 'parameter', $varname = 'undef'): bool {
3332 // Wenn keine Validierung erforderlich ist, einfach true zurückgeben
3333 if ($rules == '*') return true;
3334 // Validator-Objekt aus dem Cache holen
3335 $oValidator = dbx()->get_system_obj('dbxValidator'); // #cache for speed
3336 // Validierung durchführen
3337 return $oValidator->validate($danger_value, $rules, $varname);
3338}
3339
3340
3341
3342
3343
3457// Session
3458
3459// Session - - - - - - - - - - - - - - - - - - - - - - - - -
3460
3466function dbx_make_seed(){
3467 list($usec, $sec) = explode(' ', microtime());
3468 return (float) $sec + ((float) $usec * 100000);
3469}
3470
3477function dbx_load_cookie($cookie) {
3478 $data=array();
3479 if (isset($_COOKIE[$cookie])) $data = json_decode($_COOKIE[$cookie], true);
3480 $_SESSION['dbx']['cookie'][$cookie]=$data;
3481}
3482
3483
3484function dbx_save_cookie($cookie,$hh=12) {
3485 $data=$_SESSION['dbx']['cookie'][$cookie];
3486 setcookie($cookie, json_encode($data), time()+3600*$hh,'/');
3487}
3488
3489function dbx_delete_cookie($cookie) {
3490 setcookie($cookie, '', time() - 3600, '/');
3491}
3492
3493
3494function dbx_get_cookie_val($cookie,$key,$default='') {
3495 $val=$default;
3496 if (isset($_SESSION['dbx']['cookie'][$cookie][$key])) {
3497 $val=$_SESSION['dbx']['cookie'][$cookie][$key];
3498 }
3499 return $val;
3500}
3501
3502
3503// Format Value
3513function dbx_get_Date($date, $io, $default = ''): string {
3514 //dbx_debug("dbx_get_Date($date) io=($io) defalut=($default)");
3515 if (!$date || $date===null) $date='';
3516 $date = trim($date);
3517
3518 // Ensure the date only contains valid characters.
3519 if (!preg_match('#^[0-9./-]+$#', $date)) {
3520 dbx()->set_system_var('dbx_validate_error', 1);
3521 return $default;
3522 }
3523
3524 // Check date length.
3525 if (strlen($date) !== 10) {
3526 dbx()->set_system_var('dbx_validate_error', 1);
3527 return $default;
3528 }
3529
3530 // Determine delimiter and split the date.
3531 $delimiter = '';
3532 if (strpos($date, '-') !== false) {
3533 $delimiter = '-';
3534 } elseif (strpos($date, '.') !== false) {
3535 $delimiter = '.';
3536 } elseif (strpos($date, '/') !== false) {
3537 $delimiter = '/';
3538 }
3539
3540 if (!$delimiter) {
3541 dbx()->set_system_var('dbx_validate_error', 1);
3542 return $default;
3543 }
3544
3545 $parts = explode($delimiter, $date);
3546
3547 // Ensure valid parts based on delimiter.
3548 if (count($parts) !== 3) {
3549 dbx()->set_system_var('dbx_validate_error', 1);
3550 return $default;
3551 }
3552
3553 [$first, $second, $third] = $parts;
3554
3555 // Determine the format (DD.MM.YYYY or YYYY-MM-DD).
3556 if ($delimiter === '-') {
3557 [$year, $month, $day] = [$first, $second, $third];
3558 } else {
3559 [$day, $month, $year] = [$first, $second, $third];
3560 }
3561
3562 // Validate the extracted date.
3563 if (!checkdate((int)$month, (int)$day, (int)$year)) {
3564 dbx()->set_system_var('dbx_validate_error', 1);
3565 return $default;
3566 }
3567
3568 // Format date based on the desired output.
3569 if ($io === 'web') {
3570 return sprintf('%02d.%02d.%04d', $day, $month, $year);
3571 } elseif ($io === 'php') {
3572 return sprintf('%04d-%02d-%02d', $year, $month, $day);
3573 }
3574
3575 // Default return in case of unsupported $io value.
3576 dbx()->set_system_var('dbx_validate_error', 1);
3577 return $default;
3578}
3579
3580
3581function dbx_get_webDate($date,$default='') {
3582 $date=dbx_get_Date($date,'web');
3583 if (!$date) $date=$default;
3584 return $date;
3585}
3586
3587function dbx_get_phpDate($date,$default='') {
3588 $date=dbx_get_Date($date,'php');
3589 if (!$date) $date=$default;
3590 return $date;
3591}
3592
3593
3594
3595function dbx_get_webDateTime($date_time,$default='') {
3596 $date=substr($date_time, 0, 10);
3597 $time=substr($date_time,11, 8);
3598 $date=dbx_get_Date($date,'web');
3599 return $date.' '.$time;
3600}
3601
3602
3603// Secure
3604
3605function dbx_is_Login() {
3606 return dbx()->user('id');
3607}
3608
3617 if ($key != '*') {
3618 $_SESSION['dbx']['current_user'][$key]=$value;
3619 } else {
3620 $_SESSION['dbx']['current_user']=$value;
3621 }
3622}
3624 if (trim($value)=='') return FALSE;
3625 $lang = strlen($value);
3626 $okcahr = '-0123456789.,';
3627 for ($i = 0; $i < $lang; $i++) {
3628 $char = $value[$i];
3629 $ok = strrpos($okcahr, $char);
3630 if ($ok === FALSE) return FALSE;
3631 }
3632 return TRUE;
3633}
3634
3635
3636
3637
3638// Time
3639
3640
3641function dbx_get_Today($days=0) {
3642 $today = getdate();
3643 $date=$today['year'].'-'.$today['mon'].'-'.$today['mday'];
3644 //return $date;
3645
3646 $date_t = strtotime($date.' UTC');
3647 return gmdate('Y-m-d',$date_t + ($days*86400));
3648
3649
3650}
3651
3653 list($usec, $sec) = explode(' ',microtime());
3654 return ((float)$usec + (float)$sec);
3655}
3656
3657// File Upload
3658
3659function dbx_upload() {
3660 $oUpload=dbx()->get_system_obj('dbxUpload');
3661
3662}
3663
3664
3665// Mail
3666
3667
3668
3669
3670
3671
3672function dbx_html2txt($txt) {
3673 $txt = dbx_html2src($txt);
3674 $txt = str_replace('<br/>',"\n", $txt );
3675 $txt = str_replace('<br>' ,"\n", $txt );
3676 return $txt;
3677}
3678
3679function dbx_txt2html($txt) {
3680 $txt = str_replace("\n",'<br/>',$txt);
3681 return $txt;
3682}
3683
3684function dbx_html2src($html_in) {
3685 $html_in=stripslashes($html_in);
3686 $html_in = str_replace ('&nbsp;' , ' ', $html_in);
3687 $html_in = str_replace ('&amp;' , '&', $html_in);
3688 $html_in = str_replace ('&quot;' , '"', $html_in);
3689 $html_in = str_replace ('&#039;' , "'", $html_in);
3690 $html_in = str_replace ('&lt;' , '<', $html_in);
3691 $html_in = str_replace ('&gt;' , '>', $html_in);
3692 $html_in = str_replace ('%7B' , '{', $html_in);
3693 $html_in = str_replace ('%7D' , '}', $html_in);
3694
3695 $html_in = str_replace ('&uuml;', 'ü', $html_in);
3696 $html_in = str_replace ('&ouml;', 'ö', $html_in);
3697 $html_in = str_replace ('&auml;', 'ä', $html_in);
3698 $html_in = str_replace ('&Uuml;', 'Ü', $html_in);
3699 $html_in = str_replace ('&Ouml;', 'Ö', $html_in);
3700 $html_in = str_replace ('&Auml;', 'Ä', $html_in);
3701
3702 return $html_in;
3703}
3704
3705
3706
3707// dbx Util
3708
3709
3711 $int=dbx()->get_system_obj('dbxInterpreter');
3712 $content=$int->run($content);
3713 return $content;
3714}
3715
3716
3717
3718// crypt / decrypt
3719
3720// use \phpseclib3\Crypt\AES; // wird am anfang gemacht.
3721
3731function dbx_decrypt($content, $xkey = '', $master = '') {
3732 try {
3733 if (!$master) {
3734 $master = dbx()->get_config('dbx', 'crypt');
3735 if (!$master) {
3736 throw new Exception("Master key is not set.");
3737 }
3738 }
3739
3740 if (!$xkey) {
3741 $xkey = 'jkgj89bz7b789345%$&8t5';
3742 }
3743
3744 $crypt_key = md5($xkey . $master);
3745 $key = substr($crypt_key, 0, 16);
3746 $iv = substr($crypt_key, -16);
3747
3748 //dbx_debug("decrypt ($xkey) ($master) Key=($key) IV=($iv)");
3749
3750 $aes = new AES('cbc');
3751 $aes->setKey($key);
3752 $aes->setIV($iv);
3753
3754 $decrypt_content = $aes->decrypt($content);
3755
3756 return $decrypt_content;
3757 } catch (Exception $e) {
3758 dbx()->debug("Decryption error: " . $e->getMessage());
3759 return false;
3760 }
3761}
3762
3772function dbx_crypt($content, $xkey = '', $master = '') {
3773 try {
3774
3775 if (!$master) {
3776 $master = dbx()->get_config('dbx', 'crypt');
3777 if (!$master) {
3778 throw new Exception("Master key is not set.");
3779 }
3780 }
3781
3782 if (!$xkey) {
3783 $xkey = 'jkgj89bz7b789345%$&8t5';
3784 }
3785
3786 $crypt_key = md5($xkey . $master);
3787 $key = substr($crypt_key, 0, 16);
3788 $iv = substr($crypt_key, -16);
3789
3790 //dbx_debug("crypt ($xkey) ($master) Key=($key) IV=($iv)");
3791
3792 $aes = new AES('cbc');
3793 $aes->setKey($key);
3794 $aes->setIV($iv);
3795
3796 $crypt_content = $aes->encrypt($content);
3797
3798 return $crypt_content;
3799 } catch (Exception $e) {
3800 dbx()->debug("Encryption error: " . $e->getMessage());
3801 return false;
3802 }
3803}
$cfg
static attachResolvedContentRoute()
Bindet nach einem MISS die live aufgeloeste Content-ID an den Schreibvorgang.
static writeFullPage(string $html)
Schreibt die finale Ausgabe nach Design, Modulen, Interpreter und Filtern.
static readFullPage()
Liefert ausschliesslich eine bereits komplett gerenderte HTML-Seite.
Zentrale Laufzeit-API von dbXapp.
Definition dbxApi.php:39
get_config(string $modul='dbx', string $key='', $default=null)
Laedt die Konfiguration eines Moduls.
Definition dbxApi.php:620
get_editor_files()
Liefert die im aktuellen Request registrierten Editor-Dateien.
Definition dbxApi.php:251
editor_marker(string $kind, string $file)
Erzeugt einen HTML-Kommentar fuer den Frontend-Dateieditor.
Definition dbxApi.php:269
get_modul_obj(string $class)
Laedt und startet den Kontext fuer ein Hauptmodul.
Definition dbxApi.php:303
editor_file_path(string $file)
Liefert einen projekt-relativen Dateipfad fuer Editor-Marker.
Definition dbxApi.php:215
get_modul_var($varname, $default='', $rules='alphanum')
Liest eine Variable der aktuell aktiven Modulinstanz.
Definition dbxApi.php:519
array $editor_files
Dateien, die im aktuellen Request fuer den Editor markiert werden.
Definition dbxApi.php:42
get_system_obj(string $class, string $use='')
Laedt ein Systemobjekt aus dbx/include und bevorzugt den myX-Override.
Definition dbxApi.php:166
set_modul_var($varname, $value=null, $check_protected=true)
Setzt eine Variable der aktuell aktiven Modulinstanz.
Definition dbxApi.php:569
run_owner($owner, string $method='run',... $args)
Fuehrt eine Methode in einem Owner-Kontext aus.
Definition dbxApi.php:134
get_current_owner()
Liefert das aktuell aktive Owner-Objekt.
Definition dbxApi.php:112
use_system_class($class)
Bindet eine Systemklasse aus dbx/include ein, ohne ein Objekt zu erzeugen.
Definition dbxApi.php:426
register_editor_file(string $kind, string $file)
Registriert eine im aktuellen Request genutzte Editor-Datei.
Definition dbxApi.php:233
get_system_var(string $varname, $default='', string $rules=' *')
Liest eine globale Systemvariable des aktuellen Requests.
Definition dbxApi.php:454
get_request_var(string $varname, $default='', string $rules='parameter')
Liest GET/POST über die Request-Systemklasse und validiert den Wert.
Definition dbxApi.php:598
get_include_obj(string $class, string $modul='', string $use='')
Laedt eine Include-Klasse aus einem Modul.
Definition dbxApi.php:370
set_system_var(string $varname, $value)
Setzt eine globale Systemvariable fuer den aktuellen Request.
Definition dbxApi.php:498
action_url(string $url, string $action='', array $bindings=array())
Tokenisiert eine automatisch erkannte zustandsaendernde Route.
Definition dbxApi.php:1270
ge_stichtag()
Prueft einen projektspezifischen Stichtag.
Definition dbxApi.php:2819
is_modul($modul)
Prueft, ob ein Modulverzeichnis existiert.
Definition dbxApi.php:2201
user($key='id')
Liest einen Wert des aktuellen Benutzers.
Definition dbxApi.php:1305
dbx_add_modul(string $modul, string $action, string $work='')
Erzeugt einen Modul-String im spezifischen Format mit den angegebenen Parametern.
Definition dbxApi.php:3302
dbx_is_Login()
Definition dbxApi.php:3605
write_php_error_log(string $type, string $message, string $file='', int $line=0)
Schreibt einen PHP-Fehler mit Request-Kontext in das zentrale Protokoll.
Definition dbxApi.php:1621
dbx()
Liefert die zentrale dbXapp-API als Singleton.
Definition dbxApi.php:2805
os_path(string $path)
Normalisiert einen Pfad fuer das aktuelle Betriebssystem.
Definition dbxApi.php:1538
has_text($string, $find)
Prueft, ob ein Text einen Suchbegriff enthaelt.
Definition dbxApi.php:2286
dbx_is_decimal($value)
Definition dbxApi.php:3623
dbx_convert_charset(string $in, string $charset, string $incharset='UTF-8')
Lädt die Konfigurationsdaten eines Moduls aus einer Datei (verschlüsselt oder unverschlüsselt) und sp...
Definition dbxApi.php:3267
config_path_store(string $path, bool $dirTrailingSlash=false)
Speichert einen Installationspfad portabel relativ zum Projektstamm.
Definition dbxApi.php:1561
set_cookie_var($cookie, $key, $val)
Setzt einen Wert in einem DBX-Cookie.
Definition dbxApi.php:2275
error_log_file()
Liefert die zentrale PHP-Fehlerprotokolldatei.
Definition dbxApi.php:1592
set_config(string $modul, array $config)
Speichert die Konfiguration eines Moduls.
Definition dbxApi.php:793
dbx_convertArrayToPHPCode(array $array, string $prefix)
Konvertiert ein Array in PHP-Code, der es rekonstruiert.
Definition dbxApi.php:3190
set_local_config(string $modul, array $localConfig)
Speichert die vollstaendige lokale Konfiguration eines Moduls.
Definition dbxApi.php:841
has_group($access_groups='', $user_groups='')
Definition dbxApi.php:1410
get_base_dir(int $cutData=0)
Liefert das Basisverzeichnis der Installation.
Definition dbxApi.php:1507
esc($value)
Escaped einen Wert fuer HTML-Text und HTML-Attribute.
Definition dbxApi.php:2310
dbx_modul_translate($content, $modul='', $lng='')
Wendet die modulbezogene translate.php auf Inhalt an.
Definition dbxApi.php:3154
get_file_dir()
Liefert das files/-Verzeichnis der Installation.
Definition dbxApi.php:1524
log_missing($missing='')
Zaehlt einen fehlenden Pfad oder eine fehlende Ressource in dbxMissing.
Definition dbxApi.php:1930
is_design($design, $page='default')
Prueft, ob ein Design fuer die angegebene Seite existiert.
Definition dbxApi.php:2217
dbx_get_Microtime()
Definition dbxApi.php:3652
search_defaults(array $overrides=array())
Standard-Optionen fuer dbx|search (wie Content-Grid).
Definition dbxApi.php:2326
debug2($line)
Schreibt eine einfache Debug-Zeile in files/dbxDebug2.txt.
Definition dbxApi.php:2663
Global $_dbxCache
Definition dbxApi.php:15
parse_url($data)
Zerlegt URL-/Parameterdaten in einen Array.
Definition dbxApi.php:2416
send_mail($from, $to, string $subject='', string $body='', string $format='html', $attachments=array(), array $options=array())
Sendet eine E-Mail ueber dbxMail/PHPMailer.
Definition dbxApi.php:940
dbx_lng_name(string $base, string $lng='')
Sprachsuffix an Basisnamen haengen: content + de => content_de.
Definition dbxApi.php:3085
next_id(int $add=1)
Erzeugt eine fortlaufende ID innerhalb des DBX-Kontexts.
Definition dbxApi.php:2181
get_skin_css()
CSS-Pfad zum aktiven Skin relativ zum Projektroot.
Definition dbxApi.php:1867
dbx_get_webDateTime($date_time, $default='')
Definition dbxApi.php:3595
dbx_get_Today($days=0)
Definition dbxApi.php:3641
get_skin_class()
Body-Klassen fuer den aktiven Skin.
Definition dbxApi.php:1882
html($html)
Bereitet HTML fuer die Ausgabe auf.
Definition dbxApi.php:2296
dbx_crypt($content, $xkey='', $master='')
Encrypts content using AES-128-CBC encryption.
Definition dbxApi.php:3772
can_modul($modul)
Prueft den Zugriff auf ein Modul anhand seiner Konfiguration.
Definition dbxApi.php:1430
dbx_make_seed()
Holt und validiert eine POST-Variable.
Definition dbxApi.php:3466
set_local_config_section(string $modul, string $section, array $value)
Ersetzt genau einen lokalen Konfigurationsbereich.
Definition dbxApi.php:896
redirect($redirect, $timer=0)
Sendet einen Redirect oder Meta-Refresh.
Definition dbxApi.php:2240
get_self_url()
Liefert die Self-URL des aktuellen Requests.
Definition dbxApi.php:1497
error_type(int $errno)
Uebersetzt eine PHP-Fehlernummer in ihre symbolische Bezeichnung.
Definition dbxApi.php:1599
dbx_html2src($html_in)
Definition dbxApi.php:3684
dbx_get_cookie_val($cookie, $key, $default='')
Definition dbxApi.php:3494
action_token(string $scope='global')
Liefert ein sessiongebundenes Token fuer zustandsaendernde Link-Aktionen.
Definition dbxApi.php:1189
dbx_accessible_lngs()
Konfigurierte Sprachen aus dbx-Config.
Definition dbxApi.php:3048
dbx_make_dir(string $path)
Erstellt ein Verzeichnis und alle notwendigen Unterverzeichnisse.
Definition dbxApi.php:2941
get_content_permalink_mode()
Liefert den Permalink-Modus von dbxContent (content oder cms).
Definition dbxApi.php:1913
dbx_is_page($page, $design, $lng='')
Prueft, ob ein historisches Template unter dbx/tpl/htm existiert.
Definition dbxApi.php:2981
invalidate_action_tokens()
Verwirft alle Action-Tokens an einer Authentifizierungsgrenze.
Definition dbxApi.php:1247
get_design_skin_ids(string $design='')
Liefert die Skin-IDs, die ein Design durch eigene skin-*.css-Dateien tatsaechlich bereitstellt.
Definition dbxApi.php:1753
delete_session_var($key, $section='sys', $modul='modul')
Loescht einen strukturierten Sessionwert oder eine ganze Ebene.
Definition dbxApi.php:1115
dbx_log_missing_entry($missing='')
Definition dbxApi.php:17
json_response(array $data, bool $withRuntime=false)
Beendet den Request mit JSON-Ausgabe.
Definition dbxApi.php:1647
dbx_delete_cookie($cookie)
Definition dbxApi.php:3489
part_select($vor, $nach, $part)
Schneidet einen Teil zwischen zwei Markern aus einem Text.
Definition dbxApi.php:2390
load_content_cache_classes()
Laedt die Content-Cache-Klassen einmalig fuer Frontend, CMS und Admin.
Definition dbxApi.php:1898
dbx_get_webDate($date, $default='')
Definition dbxApi.php:3581
new_password($minlength, $special='-_!')
Erzeugt ein neues Passwort.
Definition dbxApi.php:2448
dbx_upload()
Definition dbxApi.php:3659
dbx_decrypt($content, $xkey='', $master='')
Decrypts content using AES-128-CBC encryption.
Definition dbxApi.php:3731
timestamp($add_sec=0)
Liefert einen Unix-Timestamp mit optionalem Sekunden-Offset.
Definition dbxApi.php:2362
dbx_save_cookie($cookie, $hh=12)
Definition dbxApi.php:3484
patch_local_config(string $modul, array $patch)
Fuehrt einen lokalen Konfigurationsausschnitt rekursiv zusammen.
Definition dbxApi.php:875
dbx_validate_var($danger_value, $rules='parameter', $varname='undef')
Validiert eine Eingabe basierend auf angegebenen Regeln.
Definition dbxApi.php:3331
run_web_app_request()
Fuehrt den kompletten Frontcontroller-Ablauf aus und schreibt die Response.
Definition dbxApi.php:2612
normalize_skin(string $skin='', string $design='')
Normalisiert Skin-/Farbnamen auf gueltige Skin-IDs.
Definition dbxApi.php:1813
dbx_lng_resolve_file(string $dir, string $name, string $ext, string $lng='', bool $fallback=true)
Datei mit Sprachsuffix aufloesen: name_lng.ext mit Fallback name.ext.
Definition dbxApi.php:3109
get_skin()
Aktiver Skin aus Systemvariable dbx_color.
Definition dbxApi.php:1858
dbx_sendMail($from, $fromname, $to, $subject, $text, $type='html', $attach='', $archiv=0)
Kompatibilitaetswrapper fuer dbx()->send_mail().
Definition dbxApi.php:2967
timer($section, $info='')
Misst Laufzeiten fuer Debug/Analyse.
Definition dbxApi.php:1678
dbx_txt2html($txt)
Definition dbxApi.php:3679
dbx_load_cookie($cookie)
Lädt einen JSON-Cookie in den dbxapp-Sessionbereich.
Definition dbxApi.php:3477
dbx_html2txt($txt)
Definition dbxApi.php:3672
dbx_get_phpDate($date, $default='')
Definition dbxApi.php:3587
check_action_token(string $scope='global', string $token='')
Prueft ein sessiongebundenes Aktions-Token.
Definition dbxApi.php:1206
dbx_DateTime($date_time='now', $calc=0, $special='')
Liefert ein DBX-Datum/Zeit-Format mit optionalem Offset.
Definition dbxApi.php:2894
config_path_resolve(string $path)
Loest einen gespeicherten Projektpfad in einen Betriebssystempfad auf.
Definition dbxApi.php:1582
get_base_url()
Liefert die Basis-URL des aktuellen Requests.
Definition dbxApi.php:1488
dbx_set_CurrentUser($key, $value)
Setzt einen Wert oder den gesamten aktuellen Benutzerkontext.
Definition dbxApi.php:3616
dbx_lng_current()
Lädt eine Klasse aus dem Cache oder erstellt eine neue Instanz der Klasse.
Definition dbxApi.php:3038
norep($norep, $i=0)
Lagert HTML/Text in einen norep-Platzhalter aus.
Definition dbxApi.php:2168
debug($txt, $data1='', $data2='', $data3='')
Schreibt Debug-Ausgaben in files/dbxDebug.txt, wenn Debug aktiv ist.
Definition dbxApi.php:2686
time_diff($starttime=0, $endtime=0)
Berechnet eine Zeitdifferenz zwischen zwei Timestamps.
Definition dbxApi.php:2376
get_remember_var(string $varname, $default='', string $modul='modul')
Liest einen Remember-Wert.
Definition dbxApi.php:1014
is_dbx_edit()
Prueft, ob der Frontend-Edit-Modus aktiv ist (dbx_edit > 0).
Definition dbxApi.php:1419
sys_msg($status='', $about='', $rid='', $why='', $what='')
Schreibt eine strukturierte Systemmeldung.
Definition dbxApi.php:2047
can($access_groups='', $user_groups='')
Prueft Gruppenrechte gegen den aktuellen oder uebergebenen Benutzer.
Definition dbxApi.php:1381
set_session_var($key, $val, $section='sys', $modul='')
Setzt einen strukturierten Sessionwert.
Definition dbxApi.php:1102
is_int_value($value)
Prueft, ob ein Wert als Integer verwendbar ist.
Definition dbxApi.php:2435
set_remember_var(string $varname, $value, string $modul='modul')
Setzt einen Remember-Wert.
Definition dbxApi.php:1049
dbx_get_Date($date, $io, $default='')
Validates and formats a date string based on the input and output format.
Definition dbxApi.php:3513
dbx_replace_first($search_str, $replacement_str, $src_str)
Ersetzt das erste Vorkommen einer Zeichenfolge.
Definition dbxApi.php:3173
get_session_var($key, $default=null, $section='sys', $modul='modul')
Liest einen strukturierten Sessionwert.
Definition dbxApi.php:1078
dbx_interpreter($content)
Definition dbxApi.php:3710
login($uid=0, $remember=0)
Meldet einen Benutzer im DBX-Kontext an.
Definition dbxApi.php:1465
dbx_copy_recursive($src, $dst)
Kopiert ein komplettes Verzeichnis rekursiv.
Definition dbxApi.php:2833
$_SERVER['REQUEST_METHOD']
if( $base !==$expectedBase) if($files !==$expectedBase . 'files/') $stored
if($resolved !==$expectedBase . 'files/test/') $config
$moduleDir
Architekturvertrag für die Fehlerprotokoll-Anzeige im Admin-Dashboard.
if(preg_match('/core\.js\? foreach[^"\']*v=(\d+)/', $designTemplate, $assetMatch) !== 1 || !str_contains($shopReference, 'dbxapp-Asset-Version ' . $assetMatch[1])) foreach (array( 'reference\\archive', 'provision_docs_content.php', 'dbxSelfTest') as $needle)(array('Installation'=> $installation, 'Installations-Tutorial'=> $installationTutorial, 'SelfTest'=> $selfTest) as $label=> $html)
foreach( $iterator as $file) if(! $groups) $expected
$GLOBALS['dbxMissingResourcesTestApi']
if($out !==$expected) $missing
if(trim($second) !=='second') $design
if(!defined( 'IMG_WEBP')) define( 'IMG_WEBP'
if(session_status() !==PHP_SESSION_ACTIVE) if(!defined('dbxSystem')) if(!defined( 'dbxRunAsAdmin')) dbx_get_base_dir($cutData=0)
Bootstrap-Ausnahme: liefert den portablen Installationspfad, bevor dbxApi geladen werden kann.
Definition index.php:61
exit
Definition index.php:146
dbx_get_file_dir()
Bootstrap-Ausnahme: liefert den portablen Dateipfad vor dem API-Start.
Definition index.php:72
if( $demoId<=0) foreach(array('create_date', 'create_uid', 'update_date', 'update_uid', 'owner',) as $systemField) $items
DBX schema administration.
if($cinematic===''||!str_contains($cinematic, 'data-dbx-cinema')) $page