13use \phpseclib3\Crypt\AES;
18 return function_exists(
'dbx') ? (int)
dbx()->log_missing(
$missing) : 0;
45 private array $owner_stack = array();
48 private bool $sys_msg_running =
false;
51 private array $timer_state = array();
54 private array $admin_bypass_user = array();
57 private bool $admin_bypass_user_loaded =
false;
60 private bool $admin_bypass_user_loading =
false;
71 private function push_owner(
$owner): void {
73 $this->owner_stack[] =
$owner;
82 private function pop_owner(): void {
83 if ($this->owner_stack) {
84 array_pop($this->owner_stack);
97 private function set_current_owner(
$owner): void {
99 if ($this->owner_stack) {
100 $this->owner_stack[count($this->owner_stack) - 1] =
$owner;
102 $this->owner_stack[] =
$owner;
113 if (!$this->owner_stack) {
117 return $this->owner_stack[count($this->owner_stack) - 1];
139 $this->push_owner(
$owner);
142 return $owner->$method(...$args);
169 if (!preg_match(
'/^[A-Za-z_][A-Za-z0-9_]*$/',
$class)) {
170 throw new Exception(
"Invalid system class name '$class'.");
177 $baseClass =
'\\' .
$class;
183 $baseClass =
"\\dbxUndefClass";
186 $myClass = $this->get_SysClassOverrideName(
$class);
187 $myFile = $this->ensure_SysClassOverride(
$class, $myClass, $baseClass);
189 if ($myFile && file_exists($myFile)) {
190 $this->register_editor_file(
'sysclass', $myFile);
191 require_once $myFile;
194 $myClassFull =
'\\' . $myClass;
195 $createClass = class_exists($myClassFull,
false) ? $myClassFull : $baseClass;
201 if (class_exists($createClass)) {
206 throw new Exception(
"Klasse '$createClass' konnte nicht geladen werden.");
223 return ltrim(
$file,
'/');
234 $kind = strtolower(trim($kind));
237 if ($kind ===
'' ||
$file ===
'') {
241 $path = $this->editor_file_path(
$file);
242 $key = $kind .
'|' . $path;
243 $this->editor_files[$key] = array(
'kind' => $kind,
'file' => $path);
252 return $this->editor_files;
270 $kind = strtolower(trim($kind));
272 $modes = array(
'fd' => 4,
'dd' => 5,
'class' => 6,
'sysclass' => 7,
'config' => 8);
274 if (!isset($modes[$kind]) || (
$mode !== 9 &&
$mode !== $modes[$kind]) ||
$file ===
'') {
278 $path = $this->editor_file_path(
$file);
279 $path = str_replace(
'--',
'-', $path);
281 return "\n<!-- DBX-EDITOR|$kind|$path -->\n";
305 $namespace_class =
'\dbx\-class-\-class-';
306 $namespace_class = str_replace(
'-class-',
$class, $namespace_class);
319 if (stripos(
$class,
'admin') !==
false) {
325 $modul_class_file = $this->
os_path($this->
get_base_dir() .
"dbx/modules/$class/$class.class.php");
328 if (file_exists($modul_class_file)) {
329 $this->register_editor_file(
'class', $modul_class_file);
330 require_once $modul_class_file;
333 $namespace_class =
"\\dbxUndefClass";
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);
342 $this->set_current_owner($object);
347 throw new Exception(
"Modul-Klasse '$namespace_class' konnte nicht geladen werden.");
377 $this->set_system_var(
'dbx_inc',
$class);
380 $namespace_class =
'\dbx\-modul-\-class-';
381 $namespace_class = str_replace(
'-modul-', $modul, $namespace_class);
382 $namespace_class = str_replace(
'-class-',
$class, $namespace_class);
385 $modul_class_file = $this->
os_path($this->
get_base_dir() .
"dbx/modules/$modul/include/$class.class.php");
388 if (file_exists($modul_class_file)) {
389 $this->register_editor_file(
'class', $modul_class_file);
390 require_once $modul_class_file;
393 $namespace_class =
"\\dbxUndefClass";
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);
403 $this->set_current_owner($object);
408 throw new Exception(
"Klasse '$namespace_class' konnte nicht geladen werden.");
428 $dbx_class_file=$this->
get_base_dir().
"dbx/include/".$class.
".class.php";
429 $dbx_class_file=$this->
os_path($dbx_class_file);
432 if (file_exists($dbx_class_file)) {
433 require_once $dbx_class_file;
460 if (isset(
$_SESSION[
'dbx'][
'tmp'][0][
'dbx'][$varname])) {
461 $danger_value =
$_SESSION[
'dbx'][
'tmp'][0][
'dbx'][$varname];
464 if (isset(
$_GET[$varname])) {
465 $danger_value =
$_GET[$varname];
467 if (isset(
$_POST[$varname])) {
468 $danger_value =
$_POST[$varname];
473 if (($danger_value !==
'') && ($danger_value !==
null)) {
528 if (isset(
$_SESSION[
'dbx'][
'tmp'][$mid][$modul][$varname])) {
529 $danger_value =
$_SESSION[
'dbx'][
'tmp'][$mid][$modul][$varname];
534 if (isset(
$_GET[$varname])) {
535 $danger_value =
$_GET[$varname];
538 if (isset(
$_POST[$varname])) {
539 $danger_value =
$_POST[$varname];
544 if ($danger_value !==
'' && $danger_value !==
null &&
dbx_validate_var($danger_value,
$rules, $varname)) {
572 $modul = $this->
get_system_var(
'dbx_activ_modul',
'dbx',
'parameter');
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'];
582 if (is_array($protected) && array_key_exists($varname, $protected)) {
583 dbx()->debug(
"PROTECTED ($varname)");
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");
624 if (file_exists($moduleConfigFile)) {
625 $_SESSION[
'dbx'][
'config_file'][$modul] = $moduleConfigFile;
629 $signature = $this->config_file_signature($moduleConfigFile)
630 .
'|' . $this->config_file_signature($moduleLocalConfigFile);
631 $cachedSignature = (string)(
$_SESSION[
'dbx'][
'config_signature'][$modul] ??
'');
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);
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']))));
650 $_SESSION[
'dbx'][
'config_signature'][$modul] = $signature;
657 if (!array_key_exists($key,
$config)) {
658 return $default !==
null ? $default :
'undef';
662 if (($val ===
'undef' || $val ===
'' || $val ===
null) && $default !==
null) {
679 private function read_module_config_defaults(
string $modul): array {
680 if ($modul ===
'dbx') {
685 if (!is_file($dir_file) || !is_readable($dir_file)) {
689 return $this->read_config_file($dir_file);
698 private function read_config_file(
string $dir_file): array {
699 if (!is_file($dir_file) || !is_readable($dir_file)) {
704 $content = file_get_contents($dir_file);
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");
716 }
catch (\Throwable $e) {
717 $this->
debug(
'#CFG read failed file=(' . $dir_file .
') error=(' . $e->getMessage() .
')');
720 restore_error_handler();
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;
744 private function config_file_signature(
string $file): string {
749 $mtime = @filemtime(
$file);
750 $size = @filesize(
$file);
751 return (
string)($mtime ===
false ? 0 : $mtime) .
':' . (
string)($size ===
false ? 0 : $size);
760 private function strip_local_config_values(array $runtime, array
$local, array
$base): array {
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]);
771 if (array_key_exists($name,
$base)) {
772 $runtime[$name] =
$base[$name];
774 unset($runtime[$name]);
796 if (isset(
$config[
'form-config-edit'])) unset(
$config[
'form-config-edit']);
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);
802 $config = $this->strip_local_config_values(
$config, $localConfig, $baseConfig);
804 $configStore = $this->get_system_obj(
'dbxConfigStore');
815 mkdir(
$dir, 0700,
true);
820 dbx()->debug(
"#CFG write ok=($ok) file=($dir_file)");
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);
842 if (preg_match(
'/^[A-Za-z0-9_]+$/', $modul) !== 1) {
847 if (!is_dir(
$dir) && !mkdir(
$dir, 0700,
true) && !is_dir(
$dir)) {
862 $_SESSION[
'dbx'][
'config_signature'][$modul]
864 $this->get_config($modul);
876 if (preg_match(
'/^[A-Za-z0-9_]+$/', $modul) !== 1) {
881 $this->
get_base_dir() .
"dbx/modules/$modul/cfg/config.local.php"
883 $localConfig = $this->read_config_file(
$localFile);
884 $localConfig = array_replace_recursive($localConfig, $patch);
901 if (preg_match(
'/^[A-Za-z0-9_]+$/', $modul) !== 1
902 || preg_match(
'/^[A-Za-z0-9_]+$/', $section) !== 1
908 $this->
get_base_dir() .
"dbx/modules/$modul/cfg/config.local.php"
910 $localConfig = $this->read_config_file(
$localFile);
911 $localConfig[$section] =
$value;
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');
949 $format = strtolower(trim($format));
950 if ($format ===
'txt') {
954 if ($format ===
'html') {
963 foreach ($this->normalize_mail_attachments($attachments) as $attachment) {
964 if (is_array($attachment)) {
966 (
string) ($attachment[
'path'] ?? $attachment[
'file'] ??
''),
967 (
string) ($attachment[
'disposition'] ??
'attachment'),
968 (
string) ($attachment[
'content_type'] ?? $attachment[
'type'] ??
''),
969 (
string) ($attachment[
'cid'] ??
'')
972 $mail->attachfile((
string) $attachment);
979 private function normalize_mail_attachments($attachments): array {
980 if ($attachments === null || $attachments ===
'') {
984 if (is_string($attachments)) {
985 return array_filter(array_map(
'trim', preg_split(
'/[;,]+/', $attachments)));
988 if (is_array($attachments)) {
989 if (isset($attachments[
'path']) || isset($attachments[
'file'])) {
990 return array($attachments);
1020 if ($modul ==
'modul') {
1021 $modul = $this->get_system_var(
'dbx_activ_modul',
'dbx',
'*');
1025 if (isset(
$_SESSION[
'dbx'][
'remember'][$modul][$varname])) {
1051 if ($modul ==
'modul') {
1052 $modul = $this->get_system_var(
'dbx_activ_modul',
'dbx',
'*');
1059 if ($modul ==
'dbx') {
1060 $this->set_system_var($varname,
$value);
1080 if ($modul==
'modul') $modul =$this->get_system_var(
'dbx_activ_modul' ,
'dbx');
1082 if (isset(
$_SESSION[
'dbx'][
'session'][$modul][$section][$key])) {
1083 $val=
$_SESSION[
'dbx'][
'session'][$modul][$section][$key];
1086 if (isset(
$_SESSION[
'dbx'][
'session'][$modul][$section])) {
1087 $val=
$_SESSION[
'dbx'][
'session'][$modul][$section];
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;
1116 if ($modul==
'modul') $modul =$this->get_system_var(
'dbx_activ_modul' ,
'dbx');
1118 if (isset(
$_SESSION[
'dbx'][
'session'][$modul][$section][$key])) {
1119 unset(
$_SESSION[
'dbx'][
'session'][$modul][$section][$key]);
1123 if (isset(
$_SESSION[
'dbx'][
'session'][$modul][$section])) {
1124 unset(
$_SESSION[
'dbx'][
'session'][$modul][$section]);
1127 if ($key ==
'*' && $section==
'*') {
1128 if (isset(
$_SESSION[
'dbx'][
'session'][$modul])) {
1129 unset(
$_SESSION[
'dbx'][
'session'][$modul]);
1145 private function normalize_action_scope(
string $scope): string {
1146 return preg_replace(
'/[^a-zA-Z0-9_.:-]/',
'',
$scope) ?:
'global';
1158 private function action_token_secret(): string {
1159 $secret = (string)$this->
get_session_var(
'action_token_secret',
'',
'security',
'dbx');
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');
1191 return hash_hmac(
'sha256',
'dbx-action-v2|' .
$scope, $this->action_token_secret());
1207 if (!preg_match(
'/^[a-f0-9]{64}$/',
$token)) {
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)) {
1226 $secret = (string)$this->
get_session_var(
'action_token_secret',
'',
'security',
'dbx');
1227 if (!preg_match(
'/^[a-f0-9]{64}$/', $secret)) {
1270 public function action_url(
string $url,
string $action =
'', array $bindings = array()): string {
1271 $webApp = $this->get_system_obj(
'dbxWebApp');
1277 if ($action !==
'') {
1281 $scope = is_array($policy) ? (string)($policy[
'scope'] ??
'') :
'';
1288 return (
string)
$webApp->append_route_params(
$url, array(
1306 $current_user =
$_SESSION[
'dbx'][
'current_user'] ?? array();
1308 if (defined(
'dbxRunAsAdmin') && (
int) constant(
'dbxRunAsAdmin') === 1) {
1309 $current_user = $this->get_admin_bypass_user($current_user);
1313 return $current_user;
1316 return $current_user[$key] ??
null;
1329 private function get_admin_bypass_user(array $session_user = array()): array {
1330 if ((int)($session_user[
'id'] ?? 0) === 1) {
1331 return $session_user;
1334 if ($this->admin_bypass_user_loaded || $this->admin_bypass_user_loading) {
1335 return $this->admin_bypass_user;
1338 $this->admin_bypass_user = array_merge($session_user, array(
1344 'design' => $session_user[
'design'] ??
'default',
1345 'color' => $session_user[
'color'] ??
'default',
1346 'language' => $session_user[
'language'] ??
'de',
1347 'edit' => $session_user[
'edit'] ?? 0,
1349 $this->admin_bypass_user_loading =
true;
1352 $session = $this->get_system_obj(
'dbxSession');
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;
1359 }
catch (\Throwable $e) {
1362 $this->admin_bypass_user_loading =
false;
1363 $this->admin_bypass_user_loaded =
true;
1366 return $this->admin_bypass_user;
1381 public function can($access_groups =
'', $user_groups =
'') {
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'] ??
'';
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);
1394 if ($current_user_groups && in_array(
'authenticated', $access_groups,
true) && (
int)$this->
user() > 0) {
1398 foreach ($user_groups as $role) {
1399 if ($role ===
'admin')
return 1;
1401 foreach ($access_groups as $group) {
1402 if ($group ===
'*' || $group === $role) $access = 1;
1403 if ($access)
break 2;
1410 public function has_group($access_groups =
'', $user_groups =
'') {
1411 return $this->
can($access_groups, $user_groups);
1420 return (int) $this->get_system_var(
'dbx_edit', 0,
'int') > 0;
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');
1440 if (defined(
'dbxRunAsAdmin') && (
int) constant(
'dbxRunAsAdmin') === 1) {
1443 if ((
int)$uid === 1) {
1447 $access = $install ? 1 : $this->
can(
$groups);
1449 if ($access==0) $this->set_system_var(
'dbx_noaccess_modul',
"(User=$uid Modul=$modul)");
1465 public function login($uid=0,$remember=0) {
1467 dbx()->debug(
"API dbx_login von ($old) Zu ($uid)");
1469 $oSession=$this->get_system_obj(
'dbxSession');
1470 $oSession->login($uid,$remember);
1473 $from = $this->
user(
'email');
1474 $fromname = $this->
user(
'name');
1475 $subject =
'Login ('.$from.
') on ('.
$page.
') User=('.$uid.
')';
1489 return $this->get_system_var(
'dbx_base_url',
'',
'*');
1498 return $this->get_system_var(
'dbx_self_url',
'',
'*');
1508 if (function_exists(
'dbx_get_base_dir')) {
1512 $path = str_replace(
'\\',
'/', dirname(__DIR__, 2)) .
'/';
1514 $path = str_ends_with($path,
'/Data/') ? substr($path, 0, -5) : $path;
1516 return rtrim($path,
'/') .
'/';
1525 if (function_exists(
'dbx_get_file_dir')) {
1539 $path = str_replace(array(
'\\',
'//',
'\\\\'),
'/', $path);
1540 $path = preg_replace(
'#(?<!:)//+#',
'/', $path);
1541 if (DIRECTORY_SEPARATOR ===
'\\') {
1542 $path = str_replace(
'/',
'\\', $path);
1545 $separator = DIRECTORY_SEPARATOR;
1546 if (!str_ends_with($path, $separator) && !str_contains(basename($path),
'.')) {
1547 $path .= $separator;
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);
1562 $path = str_replace(
'\\',
'/', trim($path));
1563 if ($path ===
'')
return '';
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));
1574 $path = ltrim($path,
'/');
1575 if ($dirTrailingSlash && $path !==
'') {
1576 $path = rtrim($path,
'/') .
'/';
1583 $path = str_replace(
'\\',
'/', trim($path));
1584 if ($path ===
'')
return '';
1585 if (!$this->path_is_absolute($path)) {
1594 if (!is_dir(
$dir)) @mkdir(
$dir, 0775,
true);
1595 return $dir . DIRECTORY_SEPARATOR .
'dbxError.log';
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',
1617 return $types[$errno] ??
'E_UNKNOWN';
1622 $request =
$_SERVER[
'REQUEST_METHOD'] ??
'CLI';
1623 $uri =
$_SERVER[
'REQUEST_URI'] ??
'';
1624 $ip =
$_SERVER[
'REMOTE_ADDR'] ??
'';
1626 "[%s] %s: %s in %s:%d | %s %s | IP=%s%s",
1627 date(
'Y-m-d H:i:s'),
1629 str_replace(array(
"\r",
"\n"),
' ', $message),
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();
1656 if (!headers_sent()) {
1657 header(
'Content-Type: application/json; charset=utf-8');
1660 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
1678 public function timer($section,$info=
'') {
1679 global $dbx_run_timer;
1682 $time = microtime(
true);
1683 $memory = memory_get_peak_usage();
1686 if (!isset($dbx_run_timer[$section])) {
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(
1697 'segment_start_time' => $time,
1698 'segment_start_memory' => $memory,
1702 $state = $this->timer_state[$section] ?? array();
1703 $running = (int) (
$state[
'running'] ?? (($dbx_run_timer[$section][
'end_time'] ?? -1) == -1 ? 1 : 0));
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));
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(
1718 'segment_start_time' => $segment_start_time,
1719 'segment_start_memory' => $segment_start_memory,
1720 'segments' => (
int) (
$state[
'segments'] ?? 0) + 1,
1722 } elseif ($info !==
'') {
1723 if (($dbx_run_timer[$section][
'info'] ??
'') ===
'') {
1724 $dbx_run_timer[$section][
'info'] = $info;
1727 $dbx_run_timer[$section][
'end_time'] = -1;
1728 $dbx_run_timer[$section][
'end_memory'] = -1;
1729 $this->timer_state[$section] = array(
1731 'segment_start_time' => $time,
1732 'segment_start_memory' => $memory,
1733 'segments' => (
int) (
$state[
'segments'] ?? 0),
1754 static $cache = 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;
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;
1778 $cache[
$design] = array_values($skins);
1786 private function resolve_skin_design(
string $design =
''): string {
1789 $design = (string)$this->get_system_var(
1791 $this->get_system_var(
'dbx_design',
'dbxapp')
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') {
1803 return preg_match(
'/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/',
$design) ?
$design :
'dbxapp';
1814 $skin = strtolower(trim($skin));
1825 'black' =>
'dunkel',
1827 'dunkel' =>
'dunkel',
1835 if ($skin !==
'' && isset($map[$skin])) {
1836 $skin = $map[$skin];
1839 if ($skin ===
'' || !in_array($skin, $skinIds,
true)) {
1840 $cfg = strtolower(trim((
string) $this->get_config(
'dbx',
'default_color',
'blau')));
1844 if (!in_array($skin, $skinIds,
true)) {
1845 $skin = in_array(
'blau', $skinIds,
true)
1847 : (in_array(
'hell', $skinIds,
true) ?
'hell' : (string)($skinIds[0] ??
'blau'));
1859 return $this->
normalize_skin((string) $this->get_system_var(
'dbx_color',
''));
1868 $design = $this->resolve_skin_design((string)$this->get_system_var(
1870 $this->get_system_var(
'dbx_design',
'dbxapp')
1874 return 'dbx/design/' .
$design .
'/css/skin-' . $skin .
'.css';
1884 $cls =
'skin-' . $skin;
1886 if ($skin ===
'dunkel') {
1887 $cls .=
' theme-dark';
1899 static $loaded = false;
1904 require_once $this->
os_path($this->
get_base_dir() .
'dbx/modules/dbxContent/include/dbxContent_bootstrap_sync.php');
1915 if (is_file(
$file)) {
1919 return class_exists(
'\dbx\dbxContent\dbxContentLng')
1940 $transactionStarted =
false;
1943 $db = $this->get_system_obj(
'dbxDB');
1944 if (!is_object(
$db)) {
1948 if ((
int)
$db->begin(
'dbxMissing') !== 1) {
1949 throw new \RuntimeException(
'dbxMissing-Transaktion konnte nicht gestartet werden.');
1951 $transactionStarted =
true;
1953 $uid = (int)$this->
user();
1954 $rec =
$db->select1(
'dbxMissing', array(
'missing' =>
$missing),
'id,count', 0);
1955 $request = $this->missing_request_source();
1957 if (is_array($rec) && (
int)($rec[
'id'] ?? 0) > 0) {
1958 $id = (int)$rec[
'id'];
1960 'count' => ((
int)($rec[
'count'] ?? 0)) + 1,
1962 if ($request !==
'') {
1963 $values[
'request'] = $request;
1966 if ((
int)
$db->update(
'dbxMissing', $values, $id, 0, 1, 1, 0) !== 1) {
1967 throw new \RuntimeException(
'dbxMissing-Zaehler konnte nicht aktualisiert werden.');
1969 if ((
int)
$db->commit(
'dbxMissing') !== 1) {
1970 throw new \RuntimeException(
'dbxMissing-Transaktion konnte nicht abgeschlossen werden.');
1972 $transactionStarted =
false;
1981 if ($request !==
'') {
1982 $values[
'request'] = $request;
1985 $ok =
$db->insert(
'dbxMissing', $values, 0, 1, 1, 0);
1986 $id =
$ok ? (int)
$db->get_insert_id() : 0;
1988 throw new \RuntimeException(
'dbxMissing-Eintrag konnte nicht gespeichert werden.');
1990 if ((
int)
$db->commit(
'dbxMissing') !== 1) {
1991 throw new \RuntimeException(
'dbxMissing-Transaktion konnte nicht abgeschlossen werden.');
1993 $transactionStarted =
false;
1996 }
catch (\Throwable $e) {
1997 if ($transactionStarted && isset(
$db) && is_object(
$db)) {
1998 $db->rollback(
'dbxMissing');
2000 $this->
write_php_error_log(get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
2007 private function missing_request_source(): string {
2008 $referer = trim((string)(
$_SERVER[
'HTTP_REFERER'] ??
''));
2009 if ($referer ===
'') {
2014 if (!is_array($parts)) {
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'];
2026 $source .= (string)($parts[
'path'] ??
'');
2047 public function sys_msg($status =
'', $about =
'', $rid =
'', $why =
'', $what =
'') {
2051 if ((
string)getenv(
'DBX_SELFTEST') ===
'1'
2052 && (
string)getenv(
'DBX_SELFTEST_ALLOW_SYSMSG') !==
'1') {
2056 if ($this->sys_msg_running) {
2060 $this->sys_msg_running =
true;
2063 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
2064 $caller = $trace[1] ??
null;
2065 $file = $caller[
'file'] ??
'';
2066 $line = (int)($caller[
'line'] ?? 0);
2068 $status = strtolower(trim((
string)$status));
2069 if ($status ===
'') {
2085 $level = $level_map[$status] ?? 10;
2086 if ($status ===
'warn') {
2087 $status =
'warning';
2090 $sysMsgLevel = strtolower(trim((
string) $this->get_config(
'dbx',
'sys_msg_level',
'all')));
2091 if ($sysMsgLevel ===
'') {
2092 $sysMsgLevel =
'all';
2096 if ($sysMsgLevel ===
'error') {
2098 } elseif ($sysMsgLevel ===
'warning' || $sysMsgLevel ===
'warn') {
2102 if ($level < $minLevel) {
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' ,
'',
'*');
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 ?:
'';
2115 $what_text = (string)$what;
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);
2126 'xuser' => $this->
user(
'id'),
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,
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;
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)");
2151 return (
int)$insertId;
2153 $this->sys_msg_running =
false;
2169 $norep=str_replace(
"\r",
'',$norep);
2170 $norep_id=
'norep_'.$this->next_id();
2171 $_SESSION[
'dbx'][
'norep'][$norep_id]=$norep;
2172 return '['.$norep_id.
']';
2204 $modul_class_file=$this->
get_base_dir().
"dbx/modules/$modul/".$modul.
".class.php";
2205 if (file_exists($modul_class_file)) $retval=
true;
2219 $firstchar=substr(
$design,0,1);
2220 if (!
$admin && $firstchar ==
'_')
return false;
2221 if (!
$admin && $firstchar ==
'-')
return false;
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;
2241 $timer = ($timer * 1000);
2243 $ajax = $this->get_system_var(
'dbx_ajax', 0,
'int');
2245 dbx()->debug(
"run redirect ($redirect)");
2247 if (!str_contains($redirect,
'://'))
2248 $redir =
$base . $redirect;
2252 dbx()->debug(
"#dbx_redirect Call=($redirect) redir=($redir) Ajax=($ajax) timer=($timer)");
2254 $redir_js = json_encode($redir);
2255 $allow_internal =
"if(window.dbx&&dbx.utilities&&dbx.utilities.leaveGuard)"
2256 .
"{dbx.utilities.leaveGuard.allowIfInternal($redir_js);}";
2259 $script =
"<script>$allow_internal window.location.replace($redir_js);</script>";
2261 $script =
"<script>setTimeout(function() { $allow_internal window.location.replace($redir_js); }, $timer);</script>";
2276 $_SESSION[
'dbx'][
'cookie'][$cookie][$key]=$val;
2287 return strpos(
'~'.$string,$find);
2297 return htmlentities(
$html, ENT_QUOTES);
2311 return htmlspecialchars(
2313 ENT_QUOTES | ENT_SUBSTITUTE,
2330 'placeholder' =>
'🔍',
2331 'title' =>
'Suchen',
2335 'input_class' =>
'form-control-sm dbx-grid-search',
2336 'data_role' =>
'search',
2341 'extra_attrs' =>
'',
2345 if (array_key_exists(
'placeholder', $overrides) && trim((
string) $overrides[
'placeholder']) ===
'') {
2346 unset($overrides[
'placeholder']);
2349 $data = array_merge($defaults, $overrides);
2350 if (trim((
string)$data[
'tooltip']) ===
'') {
2351 $data[
'tooltip'] = (string)$data[
'title'];
2363 list($usec, $sec) = explode(
" ",microtime());
2364 $time= ((float) $usec + (float)$sec);
2365 $time= (float) ($time + ($add_sec));
2377 if (!$starttime) $starttime=$this->
timestamp();
2378 if (!$endtime) $endtime =$this->
timestamp();
2379 return ($endtime-$starttime);
2391 $leng= strlen($vor);
2392 $pos1= strpos($part, $vor);
2394 if ($pos1 ===
false) {
2398 $part= substr($part, ($pos1+$leng));
2399 $pos2= strpos($part, $nach);
2401 if ($pos2 ===
false) {
2405 $part= substr($part, 0,$pos2);
2417 if (!is_array($data)) {
2418 $first=substr($data,0,1);
2419 if ($data &&
$first !=
'=') {
2420 if (strpos($data,
'=')) {
2421 parse_str($data,$xdata);
2436 if (is_int(
$value))
return 1;
2437 if (is_string(
$value) && filter_var(
$value, FILTER_VALIDATE_INT) !==
false)
return 1;
2449 $length = (int)$minlength;
2450 $alphabet =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' . (string)$special;
2451 if ($length < 1 || $alphabet ===
'') {
2456 $lastIndex = strlen($alphabet) - 1;
2457 for ($i = 0; $i < $length; $i++) {
2458 $password .= $alphabet[random_int(0, $lastIndex)];
2465 private function emit_http_response_body(
string $response): void {
2466 if (strtoupper((string)(
$_SERVER[
'REQUEST_METHOD'] ??
'GET')) !==
'HEAD') {
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) {
2482 session_write_close();
2485 if (!headers_sent()) {
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();
2504 $this->get_system_obj(
'dbxRuntime')->send_headers();
2505 $this->emit_http_response_body(
$html);
2510 private function render_web_app(): string {
2511 $sessionId = session_id();
2513 $this->
debug(
"#### Session #### PHP-ID=($sessionId)");
2515 $this->
timer(
'system',
'full-app');
2516 $this->
timer(
'system-load',
'load Kernel');
2518 $webApp = $this->get_system_obj(
'dbxWebApp');
2519 $session = $this->get_system_obj(
'dbxSession');
2520 $interpreter =
null;
2521 $this->
timer(
'system-load');
2523 $this->
timer(
'session-load',
'Session load');
2525 $this->
timer(
'session-load');
2527 $this->
timer(
'system-check',
'System check');
2528 $this->set_system_var(
'dbx_activ_modul',
'dbx');
2536 $sync = $this->get_request_var(
'dbx_sync', 1,
'int');
2537 $installMode = (int)$this->get_system_var(
'dbx_install', 0,
'int') === 1;
2539 if (!$installMode) {
2540 if (
$webApp->apply_canonical_home_redirect()) {
2541 $this->
timer(
'system-check');
2542 $this->
timer(
'system');
2545 if (
$webApp->apply_content_permalink_redirect()) {
2546 $this->
timer(
'system-check');
2547 $this->
timer(
'system');
2553 if (
$webApp->check_missing()) {
2558 if (\
dbx\dbxContent\dbxContentPageCache::prepareFullPageRequest()) {
2560 if ($cachedPage !==
null) {
2561 $this->serve_full_page_cache_hit($cachedPage);
2569 $this->set_system_var(
'dbx_permalink',
'');
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');
2585 $this->
timer($modul,
'Master-Modul');
2586 $moduleContent =
$webApp->run();
2587 $this->
timer($modul);
2589 $this->
timer(
'page-load',
'Page-Load');
2590 $this->
debug(
"#RUN-DBXWEBAPP SYNC=$sync");
2592 $pageContent =
$webApp->design_load($moduleContent);
2593 if ($interpreter ===
null) {
2594 $interpreter = $this->get_system_obj(
'dbxInterpreter');
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);
2603 $this->
debug(
'no sync no output');
2604 http_response_code(204);
2606 $this->
timer(
'page-load');
2607 $this->
timer(
'system');
2608 return (
string)$pageContent;
2614 $syncRequest = (int)$this->get_request_var(
'dbx_sync', 1,
'int') === 1;
2617 && class_exists(
'\\dbx\\dbxContent\\dbxContentPageCache',
false)
2618 && \
dbx\dbxContent\dbxContentPageCache::isPreparedFullPageRequest()) {
2621 ?
'#FULL-PAGE-CACHE stored exact final guest response'
2622 :
'#FULL-PAGE-CACHE final response not stored');
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) {
2632 if (!empty(
$GLOBALS[
'dbx_session_destroy_pending'])) {
2638 $this->get_system_obj(
'dbxRuntime')->send_headers();
2643 $this->emit_http_response_body(
$response);
2645 while (ob_get_level() > 0) {
2646 if (!@ob_end_flush())
break;
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();
2654 $this->
debug(
'#END#');
2665 $file = $this->
os_path($file);
2666 file_put_contents(
$file, $line, FILE_APPEND);
2686 public function debug($txt, $data1 =
'', $data2 =
'', $data3 =
'') {
2690 $debugActiv = $this->
get_file_dir() .
"dbxDebugActiv.txt";
2691 $debugActiv = $this->
os_path($debugActiv);
2692 if (file_exists($debugActiv)) {
2704 $file = $this->
os_path($file);
2706 foreach (array($data1, $data2, $data3) as $data) {
2707 if (is_array($data)) {
2708 $vars .= print_r($data,
true);
2711 $vars .= $data .
"\n";
2716 $txt .=
"\n" . $vars .
"\n";
2717 file_put_contents(
$file, $txt, FILE_APPEND);
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);
2748 private function ensure_SysClassOverride(
string $class,
string $myClass,
string $baseClass): string {
2749 if ($baseClass ===
"\\dbxUndefClass" || !class_exists($baseClass, false)) {
2755 $file = $this->
os_path($sysDir . $myClass .
'.class.php');
2757 if (!is_dir($sysDir)) {
2758 mkdir($sysDir, 0777,
true);
2762 if (!is_dir($cfgDir)) {
2763 mkdir($cfgDir, 0777,
true);
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");
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");
2776 if (!file_exists(
$file)) {
2779 $content .=
" * Auto-generated DBX system class override.\n";
2780 $content .=
" * Requested class: $class\n";
2781 $content .=
" * Override class: $myClass\n";
2783 $content .=
"class $myClass extends $class {\n";
2807 if (
$api ===
null) {
2820 $heute =
new DateTime();
2821 $grenze =
new DateTime(
'2025-06-01');
2822 return $heute >= $grenze;
2834 $src = rtrim($src,
'/\\');
2835 $dst = rtrim($dst,
'/\\');
2837 if (!is_dir($src)) {
2838 dbx()->debug(
"dbx_copy_recursive Error DIR");
2842 if (!file_exists($dst)) {
2843 if (!mkdir($dst, 0777,
true)) {
2844 dbx()->debug(
"dbx_copy_recursive mkdir Error($dst)");
2850 foreach (
$items as $item) {
2851 if ($item ===
'.' || $item ===
'..') {
2855 $srcPath = $src . DIRECTORY_SEPARATOR . $item;
2856 $dstPath = $dst . DIRECTORY_SEPARATOR . $item;
2858 if (is_dir($srcPath)) {
2861 dbx()->debug(
"dbx_copy_recursive Error A");
2866 if (!copy($srcPath, $dstPath)) {
2867 dbx()->debug(
"dbx_copy_recursive Error B");
2895 $timezone =
'Europe/Berlin';
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));
2903 $offset = (60*60*$offset);
2904 $calc=($calc + $offset);
2905 $date_time = date(
"Y-m-d H:i:s", (strtotime($date_time) + $calc ));
2909 $time=strtotime($date_time);
2910 $date_time=date(
"Y-m-d H:i:s", strtotime($special, $time));
2914 $week_start = strtotime(
'last Sunday', time());
2915 $week_end = strtotime(
'next Sunday', time());
2917 $month_start = strtotime(
'first day of this month', time());
2918 $month_end = strtotime(
'last day of this month', time());
2920 $year_start = strtotime(
'first day of January', time());
2921 $year_end = strtotime(
'last day of December', time());
2943 if (is_dir($path)) return 1;
2946 if (mkdir($path, 0777,
true)) {
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);
2983 $page_tpl=
dbx()->get_base_dir().
"dbx/tpl/htm/$page.htm";
2984 if (file_exists($page_tpl)) $retval=
true;
3039 $lng = strtolower(trim((string)
dbx()->get_system_var(
'dbx_lng',
'de')));
3049 $raw =
dbx()->get_config(
'dbx',
'accessible_lng',
'de');
3050 if ($raw ===
'undef' || $raw ===
'' || $raw ===
null) {
3053 if (is_array($raw)) {
3055 foreach ($raw as $val) {
3056 $val = strtolower(trim((
string) $val));
3057 if ($val !==
'' && $val !==
'undef' && preg_match(
'/^[a-z]{2,3}$/', $val)) {
3061 return count(
$out) ?
$out : array(
'de');
3064 $parts = preg_split(
'/\s*,\s*/', (
string) $raw, -1, PREG_SPLIT_NO_EMPTY);
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)) {
3075 return count(
$out) ?
$out : array(
'de');
3110 $dir = str_replace(
'\\',
'/',
$dir);
3111 if (
$dir !==
'' && substr(
$dir, -1) !==
'/') {
3115 $name = strtolower(trim($name));
3116 $ext = ltrim(strtolower(trim($ext)),
'.');
3117 if ($name ===
'' || $ext ===
'') {
3123 $pathLng =
$dir . $name .
'_' .
$lng .
'.' . $ext;
3124 if (is_file($pathLng)) {
3125 return dbx()->os_path($pathLng);
3133 $pathDef =
$dir . $name .
'.' . $ext;
3134 if (is_file($pathDef)) {
3135 return dbx()->os_path($pathDef);
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)) {
3174 return (
false !== ($pos = strpos($src_str, $search_str))) ? substr_replace($src_str, $replacement_str, $pos, strlen($search_str)) : $src_str;
3195 $keyPart = is_numeric($key) ?
"[$key]" :
"['" . addslashes($key) .
"']";
3204 $formattedValue =
"'" . addslashes(
$value) .
"'";
3205 } elseif (is_bool(
$value)) {
3207 $formattedValue =
$value ?
'true' :
'false';
3208 } elseif (
$value ===
null) {
3210 $formattedValue =
'null';
3213 $formattedValue =
$value;
3217 $code .=
"$prefix$keyPart = $formattedValue;\n";
3269 if ($charset !== $incharset) {
3272 'ä' => chr(228),
'ö' => chr(246),
'ü' => chr(252),
'ß' => chr(223),
3273 'Ä' => chr(196),
'Ö' => chr(214),
'Ü' => chr(220)
3275 $in = str_replace(array_keys($umlaute), array_values($umlaute), $in);
3278 $in = mb_convert_encoding(
3281 mb_detect_encoding($in,
"UTF-8, $charset, ISO-8859-1, ISO-8859-15",
true)
3304 $content =
'[modul=' . $modul .
']dbx_run1=' . $action;
3307 if (!empty(
$work)) {
3335 $oValidator =
dbx()->get_system_obj(
'dbxValidator');
3337 return $oValidator->validate($danger_value,
$rules, $varname);
3467 list($usec, $sec) = explode(
' ', microtime());
3468 return (
float) $sec + ((float) $usec * 100000);
3479 if (isset(
$_COOKIE[$cookie])) $data = json_decode(
$_COOKIE[$cookie],
true);
3480 $_SESSION[
'dbx'][
'cookie'][$cookie]=$data;
3485 $data=
$_SESSION[
'dbx'][
'cookie'][$cookie];
3486 setcookie($cookie, json_encode($data), time()+3600*$hh,
'/');
3490 setcookie($cookie,
'', time() - 3600,
'/');
3496 if (isset(
$_SESSION[
'dbx'][
'cookie'][$cookie][$key])) {
3497 $val=
$_SESSION[
'dbx'][
'cookie'][$cookie][$key];
3515 if (!$date || $date===null) $date=
'';
3516 $date = trim($date);
3519 if (!preg_match(
'#^[0-9./-]+$#', $date)) {
3520 dbx()->set_system_var(
'dbx_validate_error', 1);
3525 if (strlen($date) !== 10) {
3526 dbx()->set_system_var(
'dbx_validate_error', 1);
3532 if (strpos($date,
'-') !==
false) {
3534 } elseif (strpos($date,
'.') !==
false) {
3536 } elseif (strpos($date,
'/') !==
false) {
3541 dbx()->set_system_var(
'dbx_validate_error', 1);
3545 $parts = explode($delimiter, $date);
3548 if (count($parts) !== 3) {
3549 dbx()->set_system_var(
'dbx_validate_error', 1);
3556 if ($delimiter ===
'-') {
3563 if (!checkdate((
int)$month, (
int)$day, (
int)$year)) {
3564 dbx()->set_system_var(
'dbx_validate_error', 1);
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);
3576 dbx()->set_system_var(
'dbx_validate_error', 1);
3583 if (!$date) $date=$default;
3589 if (!$date) $date=$default;
3596 $date=substr($date_time, 0, 10);
3597 $time=substr($date_time,11, 8);
3599 return $date.
' '.$time;
3606 return dbx()->user(
'id');
3624 if (trim(
$value)==
'')
return FALSE;
3626 $okcahr =
'-0123456789.,';
3627 for ($i = 0; $i < $lang; $i++) {
3629 $ok = strrpos($okcahr, $char);
3630 if (
$ok === FALSE)
return FALSE;
3643 $date=$today[
'year'].
'-'.$today[
'mon'].
'-'.$today[
'mday'];
3646 $date_t = strtotime($date.
' UTC');
3647 return gmdate(
'Y-m-d',$date_t + ($days*86400));
3653 list($usec, $sec) = explode(
' ',microtime());
3654 return ((
float)$usec + (
float)$sec);
3660 $oUpload=
dbx()->get_system_obj(
'dbxUpload');
3674 $txt = str_replace(
'<br/>',
"\n", $txt );
3675 $txt = str_replace(
'<br>' ,
"\n", $txt );
3680 $txt = str_replace(
"\n",
'<br/>',$txt);
3685 $html_in=stripslashes($html_in);
3686 $html_in = str_replace (
' ' ,
' ', $html_in);
3687 $html_in = str_replace (
'&' ,
'&', $html_in);
3688 $html_in = str_replace (
'"' ,
'"', $html_in);
3689 $html_in = str_replace (
''' ,
"'", $html_in);
3690 $html_in = str_replace (
'<' ,
'<', $html_in);
3691 $html_in = str_replace (
'>' ,
'>', $html_in);
3692 $html_in = str_replace (
'%7B' ,
'{', $html_in);
3693 $html_in = str_replace (
'%7D' ,
'}', $html_in);
3695 $html_in = str_replace (
'ü',
'ü', $html_in);
3696 $html_in = str_replace (
'ö',
'ö', $html_in);
3697 $html_in = str_replace (
'ä',
'ä', $html_in);
3698 $html_in = str_replace (
'Ü',
'Ü', $html_in);
3699 $html_in = str_replace (
'Ö',
'Ö', $html_in);
3700 $html_in = str_replace (
'Ä',
'Ä', $html_in);
3711 $int=
dbx()->get_system_obj(
'dbxInterpreter');
3734 $master =
dbx()->get_config(
'dbx',
'crypt');
3736 throw new Exception(
"Master key is not set.");
3741 $xkey =
'jkgj89bz7b789345%$&8t5';
3744 $crypt_key = md5($xkey . $master);
3745 $key = substr($crypt_key, 0, 16);
3746 $iv = substr($crypt_key, -16);
3750 $aes =
new AES(
'cbc');
3754 $decrypt_content = $aes->decrypt(
$content);
3756 return $decrypt_content;
3757 }
catch (Exception $e) {
3758 dbx()->debug(
"Decryption error: " . $e->getMessage());
3776 $master =
dbx()->get_config(
'dbx',
'crypt');
3778 throw new Exception(
"Master key is not set.");
3783 $xkey =
'jkgj89bz7b789345%$&8t5';
3786 $crypt_key = md5($xkey . $master);
3787 $key = substr($crypt_key, 0, 16);
3788 $iv = substr($crypt_key, -16);
3792 $aes =
new AES(
'cbc');
3796 $crypt_content = $aes->encrypt(
$content);
3798 return $crypt_content;
3799 }
catch (Exception $e) {
3800 dbx()->debug(
"Encryption error: " . $e->getMessage());
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.
get_config(string $modul='dbx', string $key='', $default=null)
Laedt die Konfiguration eines Moduls.
get_editor_files()
Liefert die im aktuellen Request registrierten Editor-Dateien.
editor_marker(string $kind, string $file)
Erzeugt einen HTML-Kommentar fuer den Frontend-Dateieditor.
get_modul_obj(string $class)
Laedt und startet den Kontext fuer ein Hauptmodul.
editor_file_path(string $file)
Liefert einen projekt-relativen Dateipfad fuer Editor-Marker.
get_modul_var($varname, $default='', $rules='alphanum')
Liest eine Variable der aktuell aktiven Modulinstanz.
array $editor_files
Dateien, die im aktuellen Request fuer den Editor markiert werden.
get_system_obj(string $class, string $use='')
Laedt ein Systemobjekt aus dbx/include und bevorzugt den myX-Override.
set_modul_var($varname, $value=null, $check_protected=true)
Setzt eine Variable der aktuell aktiven Modulinstanz.
run_owner($owner, string $method='run',... $args)
Fuehrt eine Methode in einem Owner-Kontext aus.
get_current_owner()
Liefert das aktuell aktive Owner-Objekt.
use_system_class($class)
Bindet eine Systemklasse aus dbx/include ein, ohne ein Objekt zu erzeugen.
register_editor_file(string $kind, string $file)
Registriert eine im aktuellen Request genutzte Editor-Datei.
get_system_var(string $varname, $default='', string $rules=' *')
Liest eine globale Systemvariable des aktuellen Requests.
get_request_var(string $varname, $default='', string $rules='parameter')
Liest GET/POST über die Request-Systemklasse und validiert den Wert.
get_include_obj(string $class, string $modul='', string $use='')
Laedt eine Include-Klasse aus einem Modul.
set_system_var(string $varname, $value)
Setzt eine globale Systemvariable fuer den aktuellen Request.
action_url(string $url, string $action='', array $bindings=array())
Tokenisiert eine automatisch erkannte zustandsaendernde Route.
ge_stichtag()
Prueft einen projektspezifischen Stichtag.
is_modul($modul)
Prueft, ob ein Modulverzeichnis existiert.
user($key='id')
Liest einen Wert des aktuellen Benutzers.
dbx_add_modul(string $modul, string $action, string $work='')
Erzeugt einen Modul-String im spezifischen Format mit den angegebenen Parametern.
write_php_error_log(string $type, string $message, string $file='', int $line=0)
Schreibt einen PHP-Fehler mit Request-Kontext in das zentrale Protokoll.
dbx()
Liefert die zentrale dbXapp-API als Singleton.
os_path(string $path)
Normalisiert einen Pfad fuer das aktuelle Betriebssystem.
has_text($string, $find)
Prueft, ob ein Text einen Suchbegriff enthaelt.
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...
config_path_store(string $path, bool $dirTrailingSlash=false)
Speichert einen Installationspfad portabel relativ zum Projektstamm.
set_cookie_var($cookie, $key, $val)
Setzt einen Wert in einem DBX-Cookie.
error_log_file()
Liefert die zentrale PHP-Fehlerprotokolldatei.
set_config(string $modul, array $config)
Speichert die Konfiguration eines Moduls.
dbx_convertArrayToPHPCode(array $array, string $prefix)
Konvertiert ein Array in PHP-Code, der es rekonstruiert.
set_local_config(string $modul, array $localConfig)
Speichert die vollstaendige lokale Konfiguration eines Moduls.
has_group($access_groups='', $user_groups='')
get_base_dir(int $cutData=0)
Liefert das Basisverzeichnis der Installation.
esc($value)
Escaped einen Wert fuer HTML-Text und HTML-Attribute.
dbx_modul_translate($content, $modul='', $lng='')
Wendet die modulbezogene translate.php auf Inhalt an.
get_file_dir()
Liefert das files/-Verzeichnis der Installation.
log_missing($missing='')
Zaehlt einen fehlenden Pfad oder eine fehlende Ressource in dbxMissing.
is_design($design, $page='default')
Prueft, ob ein Design fuer die angegebene Seite existiert.
search_defaults(array $overrides=array())
Standard-Optionen fuer dbx|search (wie Content-Grid).
debug2($line)
Schreibt eine einfache Debug-Zeile in files/dbxDebug2.txt.
parse_url($data)
Zerlegt URL-/Parameterdaten in einen Array.
send_mail($from, $to, string $subject='', string $body='', string $format='html', $attachments=array(), array $options=array())
Sendet eine E-Mail ueber dbxMail/PHPMailer.
dbx_lng_name(string $base, string $lng='')
Sprachsuffix an Basisnamen haengen: content + de => content_de.
next_id(int $add=1)
Erzeugt eine fortlaufende ID innerhalb des DBX-Kontexts.
get_skin_css()
CSS-Pfad zum aktiven Skin relativ zum Projektroot.
dbx_get_webDateTime($date_time, $default='')
get_skin_class()
Body-Klassen fuer den aktiven Skin.
html($html)
Bereitet HTML fuer die Ausgabe auf.
dbx_crypt($content, $xkey='', $master='')
Encrypts content using AES-128-CBC encryption.
can_modul($modul)
Prueft den Zugriff auf ein Modul anhand seiner Konfiguration.
dbx_make_seed()
Holt und validiert eine POST-Variable.
set_local_config_section(string $modul, string $section, array $value)
Ersetzt genau einen lokalen Konfigurationsbereich.
redirect($redirect, $timer=0)
Sendet einen Redirect oder Meta-Refresh.
get_self_url()
Liefert die Self-URL des aktuellen Requests.
error_type(int $errno)
Uebersetzt eine PHP-Fehlernummer in ihre symbolische Bezeichnung.
dbx_get_cookie_val($cookie, $key, $default='')
action_token(string $scope='global')
Liefert ein sessiongebundenes Token fuer zustandsaendernde Link-Aktionen.
dbx_accessible_lngs()
Konfigurierte Sprachen aus dbx-Config.
dbx_make_dir(string $path)
Erstellt ein Verzeichnis und alle notwendigen Unterverzeichnisse.
get_content_permalink_mode()
Liefert den Permalink-Modus von dbxContent (content oder cms).
dbx_is_page($page, $design, $lng='')
Prueft, ob ein historisches Template unter dbx/tpl/htm existiert.
invalidate_action_tokens()
Verwirft alle Action-Tokens an einer Authentifizierungsgrenze.
get_design_skin_ids(string $design='')
Liefert die Skin-IDs, die ein Design durch eigene skin-*.css-Dateien tatsaechlich bereitstellt.
delete_session_var($key, $section='sys', $modul='modul')
Loescht einen strukturierten Sessionwert oder eine ganze Ebene.
dbx_log_missing_entry($missing='')
json_response(array $data, bool $withRuntime=false)
Beendet den Request mit JSON-Ausgabe.
dbx_delete_cookie($cookie)
part_select($vor, $nach, $part)
Schneidet einen Teil zwischen zwei Markern aus einem Text.
load_content_cache_classes()
Laedt die Content-Cache-Klassen einmalig fuer Frontend, CMS und Admin.
dbx_get_webDate($date, $default='')
new_password($minlength, $special='-_!')
Erzeugt ein neues Passwort.
dbx_decrypt($content, $xkey='', $master='')
Decrypts content using AES-128-CBC encryption.
timestamp($add_sec=0)
Liefert einen Unix-Timestamp mit optionalem Sekunden-Offset.
dbx_save_cookie($cookie, $hh=12)
patch_local_config(string $modul, array $patch)
Fuehrt einen lokalen Konfigurationsausschnitt rekursiv zusammen.
dbx_validate_var($danger_value, $rules='parameter', $varname='undef')
Validiert eine Eingabe basierend auf angegebenen Regeln.
run_web_app_request()
Fuehrt den kompletten Frontcontroller-Ablauf aus und schreibt die Response.
normalize_skin(string $skin='', string $design='')
Normalisiert Skin-/Farbnamen auf gueltige Skin-IDs.
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.
get_skin()
Aktiver Skin aus Systemvariable dbx_color.
dbx_sendMail($from, $fromname, $to, $subject, $text, $type='html', $attach='', $archiv=0)
Kompatibilitaetswrapper fuer dbx()->send_mail().
timer($section, $info='')
Misst Laufzeiten fuer Debug/Analyse.
dbx_load_cookie($cookie)
Lädt einen JSON-Cookie in den dbxapp-Sessionbereich.
dbx_get_phpDate($date, $default='')
check_action_token(string $scope='global', string $token='')
Prueft ein sessiongebundenes Aktions-Token.
dbx_DateTime($date_time='now', $calc=0, $special='')
Liefert ein DBX-Datum/Zeit-Format mit optionalem Offset.
config_path_resolve(string $path)
Loest einen gespeicherten Projektpfad in einen Betriebssystempfad auf.
get_base_url()
Liefert die Basis-URL des aktuellen Requests.
dbx_set_CurrentUser($key, $value)
Setzt einen Wert oder den gesamten aktuellen Benutzerkontext.
dbx_lng_current()
Lädt eine Klasse aus dem Cache oder erstellt eine neue Instanz der Klasse.
norep($norep, $i=0)
Lagert HTML/Text in einen norep-Platzhalter aus.
debug($txt, $data1='', $data2='', $data3='')
Schreibt Debug-Ausgaben in files/dbxDebug.txt, wenn Debug aktiv ist.
time_diff($starttime=0, $endtime=0)
Berechnet eine Zeitdifferenz zwischen zwei Timestamps.
get_remember_var(string $varname, $default='', string $modul='modul')
Liest einen Remember-Wert.
is_dbx_edit()
Prueft, ob der Frontend-Edit-Modus aktiv ist (dbx_edit > 0).
sys_msg($status='', $about='', $rid='', $why='', $what='')
Schreibt eine strukturierte Systemmeldung.
can($access_groups='', $user_groups='')
Prueft Gruppenrechte gegen den aktuellen oder uebergebenen Benutzer.
set_session_var($key, $val, $section='sys', $modul='')
Setzt einen strukturierten Sessionwert.
is_int_value($value)
Prueft, ob ein Wert als Integer verwendbar ist.
set_remember_var(string $varname, $value, string $modul='modul')
Setzt einen Remember-Wert.
dbx_get_Date($date, $io, $default='')
Validates and formats a date string based on the input and output format.
dbx_replace_first($search_str, $replacement_str, $src_str)
Ersetzt das erste Vorkommen einer Zeichenfolge.
get_session_var($key, $default=null, $section='sys', $modul='modul')
Liest einen strukturierten Sessionwert.
dbx_interpreter($content)
login($uid=0, $remember=0)
Meldet einen Benutzer im DBX-Kontext an.
dbx_copy_recursive($src, $dst)
Kopiert ein komplettes Verzeichnis rekursiv.
$_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)
$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.
dbx_get_file_dir()
Bootstrap-Ausnahme: liefert den portablen Dateipfad vor dem API-Start.
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