diff --git a/config/base_db.php b/config/base_db.php index 58c4921..fad903c 100644 --- a/config/base_db.php +++ b/config/base_db.php @@ -3,12 +3,22 @@ declare(strict_types=1); /** * Base database for Nexus core (users, settings, modules). - * Sync copies the correct file into /config. + * Prefer the deployed root config, but fall back to checked-in env defaults. */ -$path = __DIR__ . '/db_settings_basic.php'; -if (!file_exists($path)) { - throw new RuntimeException('Missing base DB config: expected config/db_settings_basic.php'); +$candidates = [ + __DIR__ . '/db_settings_basic.php', + __DIR__ . '/staging/db_settings_basic.php', + __DIR__ . '/prod/db_settings_basic.php', +]; + +foreach ($candidates as $path) { + if (is_file($path)) { + return require $path; + } } -return require $path; +throw new RuntimeException( + 'Missing base DB config. Expected one of: ' + . implode(', ', array_map(static fn (string $path): string => basename(dirname($path)) . '/' . basename($path), $candidates)) +); diff --git a/config/prod/db_settings_basic.php b/config/prod/db_settings_basic.php index df5a703..8bda9cf 100755 --- a/config/prod/db_settings_basic.php +++ b/config/prod/db_settings_basic.php @@ -26,6 +26,7 @@ $pgsql = [ 'host' => 'db_nexus', 'port' => 5432, 'dbname' => 'nexus_live', + 'connect_timeout' => 5, // optional: schema/search_path (commonly "public") 'schema' => 'public', diff --git a/config/staging/db_settings_basic.php b/config/staging/db_settings_basic.php index 042b74a..740e63a 100755 --- a/config/staging/db_settings_basic.php +++ b/config/staging/db_settings_basic.php @@ -26,6 +26,7 @@ $pgsql = [ 'host' => 'staging_db_nexus', 'port' => 5432, 'dbname' => 'nexus_staging', + 'connect_timeout' => 5, // optional: schema/search_path (commonly "public") 'schema' => 'public', diff --git a/public/index.php b/public/index.php index 962d3b8..f3b9569 100644 --- a/public/index.php +++ b/public/index.php @@ -1,100 +1,389 @@ - - - - - - Nexus Wartungstest - - - -
-
Wartungstest
-

Nexus ist testweise im Wartungsmodus

-

Diese Seite wird direkt aus public/index.php ausgeliefert und umgeht die normale App-Initialisierung.

-

Wenn diese Seite stabil erscheint, liegt das Problem sehr wahrscheinlich in der PHP-Anwendung, in einem Modul oder in deren Abhängigkeiten und nicht in der grundlegenden Webserver-Auslieferung.

-
- Testzeit:
- Datei: -
-
- - + $target = $pagesBase . '/modules/setup.php'; +} elseif (str_starts_with($uriPath, 'modules/access/')) { + $_GET['module'] = trim(substr($uriPath, strlen('modules/access/')), '/'); + $target = $pagesBase . '/modules/access.php'; +} elseif ($uriPath === 'modules/sql-import') { + $target = $pagesBase . '/modules/sql_import.php'; +} elseif ($uriPath === 'auth/login') { + $target = $pagesBase . '/auth/login.php'; +} elseif ($uriPath === 'auth/callback') { + $target = $pagesBase . '/auth/callback.php'; +} elseif ($uriPath === 'auth/logout') { + $target = $pagesBase . '/auth/logout.php'; +} elseif ($uriPath === 'settings') { + $target = $pagesBase . '/users/settings.php'; +} elseif ($uriPath === 'settings/widgets') { + $target = $pagesBase . '/users/settings_widgets.php'; +} elseif ($uriPath === 'settings/search-engines') { + $target = $pagesBase . '/users/settings_search_engines.php'; +} elseif ($uriPath === 'settings/apps') { + $target = $pagesBase . '/users/settings_apps.php'; +} elseif ($uriPath === 'users') { + $target = $pagesBase . '/users/index.php'; +} elseif ($uriPath === 'dashboard') { + $target = $pagesBase . '/dashboard.php'; +} elseif ($uriPath === 'dashboards') { + $target = $pagesBase . '/dashboards.php'; +} elseif ($uriPath === 'integrations') { + $target = $pagesBase . '/integrations.php'; +} elseif ($uriPath === 'page-modules') { + $target = $pagesBase . '/page_modules.php'; +} elseif (preg_match('~^page-modules/view/(\d+)$~', $uriPath, $pageModuleMatch)) { + $_GET['id'] = (string) $pageModuleMatch[1]; + $target = $pagesBase . '/page_modules_view.php'; +} elseif ($uriPath === 'debug') { + $target = $pagesBase . '/retool/debug.php'; +} elseif (preg_match('~^module/([a-zA-Z0-9_-]+)(?:/(.+))?$~', $uriPath, $m)) { + $module = $m[1]; + $page = isset($m[2]) && $m[2] !== '' ? trim($m[2], '/') : 'index'; + $moduleMeta = app()->modules()->get($module); + if ($moduleMeta !== null) { + $auth->requireModuleAccess($moduleMeta); + } + $modulePage = app()->modules()->resolvePage($module, $page); + $moduleBootstrap = $projectRoot . '/modules/' . $module . '/bootstrap.php'; + if (is_file($moduleBootstrap)) { + require_once $moduleBootstrap; + } + if ($modulePage) { + $target = $modulePage; + } else { + http_response_code(404); + $target = $page404; + } +} elseif ($uriPath === '' || $uriPath === 'index' || $uriPath === 'index.php') { + $target = $pagesBase . '/index.php'; +} else { + $base = $pagesBase . '/' . $uriPath; + // 1) Verzeichnis mit index.php + if (is_dir($base) && is_file($base . '/index.php')) { + $target = $base . '/index.php'; + } + // 2) Datei + elseif (is_file($base . '.php')) { + + $target = $base . '.php'; + } + // 3) 404 + elseif (is_file($base)) { + + $target = $base; + } + // 3) 404 + else { + http_response_code(404); + $target = $page404; + } +} +// ------------------------------------ +// Layout-Regel +// ------------------------------------ +$skipLayout = false; +$targetReal = realpath($target); +$retoolBase = realpath($pagesBase . '/retool/raw'); + +// Beispiel: alles unter landingpages/retool/* ohne Layout +if ($targetReal && $retoolBase && str_starts_with($targetReal, $retoolBase)) { + $skipLayout = true; +} + +// ------------------------------------ +// Ausgabe +// ------------------------------------ +// Erst Inhalt laden (ohne Ausgabe), damit Header/Redirects vor HTML funktionieren +ob_start(); +try { + require $target; + $content = ob_get_clean(); +} catch (\App\ModuleConfigException $e) { + ob_end_clean(); + http_response_code(412); + $moduleName = $e->module(); + $module = app()->modules()->get($moduleName); + $title = $module['title'] ?? $moduleName; + $setupUrl = '/modules/setup/' . rawurlencode($moduleName); + $content = '
' . + '
' . e($title) . '
' . + '

Setup erforderlich

' . + '

' . e($e->getMessage()) . '

' . + '
Zum Setup
' . + '
'; +} + +// Wenn bereits Header gesendet wurden (z. B. eigener Redirect/Content-Type), Layout überspringen +if (headers_sent()) { + $skipLayout = true; +} + +if (!$skipLayout) { + tpl('layout_start', 'structure'); +} + +echo $content; + +if (!$skipLayout) { + tpl('layout_end', 'structure'); +} diff --git a/src/App/Database.php b/src/App/Database.php index a798b16..dfefab7 100755 --- a/src/App/Database.php +++ b/src/App/Database.php @@ -213,14 +213,21 @@ final class Database $host = (string)($db['host'] ?? 'localhost'); $port = (int)($db['port'] ?? 5432); + $connectTimeout = isset($db['connect_timeout']) ? max(1, (int) $db['connect_timeout']) : null; // Hinweis: charset gehört bei pgsql nicht in den DSN - return sprintf( + $dsn = sprintf( 'pgsql:host=%s;port=%d;dbname=%s', $host, $port, (string)$db['dbname'] ); + + if ($connectTimeout !== null) { + $dsn .= ';connect_timeout=' . $connectTimeout; + } + + return $dsn; } private static function buildSqliteDsn(array $db): string