This commit is contained in:
2026-03-02 02:02:41 +01:00
parent 3102790842
commit 28bd5f4e95
7 changed files with 119 additions and 174 deletions

View File

@@ -6,20 +6,14 @@ ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
// Pick config set: first try root files, otherwise fall back to env dir (prod/staging/...)
$appEnvFromEnv = getenv('APP_ENV') ?: 'prod';
$envDir = rtrim(__DIR__, '/\\') . '/' . $appEnvFromEnv;
foreach (['domaindata.php','settings.php'] as $cfgFile) {
// Required config files live in /config (sync copies staging/prod here)
foreach (['domaindata.php', 'settings.php'] as $cfgFile) {
$rootPath = __DIR__ . '/' . $cfgFile;
$envPath = $envDir . '/' . $cfgFile;
if (file_exists($rootPath)) {
require_once $rootPath;
} elseif (file_exists($envPath)) {
require_once $envPath;
} else {
throw new \RuntimeException("Missing required config file: $cfgFile (looked for $rootPath or $envPath)");
throw new \RuntimeException("Missing required config file: $cfgFile (expected $rootPath)");
}
}

View File

@@ -28,10 +28,9 @@ spl_autoload_register(function ($class) {
// 2. Funktionen laden
require_once __DIR__ . '/../src/App/functions.php';
// 3. Konfiguration laden
// Wir simulieren hier den Sync-Prozess: Wenn config/db.php nicht da ist, nimm staging.
$configFile = file_exists(__DIR__ . '/db.php') ? __DIR__ . '/db.php' : __DIR__ . '/staging/db.php';
$settingsFile = file_exists(__DIR__ . '/settings.php') ? __DIR__ . '/settings.php' : __DIR__ . '/staging/settings.php';
// 3. Konfiguration laden (nur Root-Dateien; Sync kopiert staging/prod hierher)
$settingsFile = __DIR__ . '/settings.php';
$configFile = __DIR__ . '/db.php';
if (file_exists($settingsFile)) {
require_once $settingsFile;

View File

@@ -1,11 +0,0 @@
</div>
</main>
<footer class="bg-gray-800 border-t border-gray-700 mt-auto">
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
<p class="text-center text-gray-500 text-xs">&copy; <?= date('Y') ?> Nexus Control Panel. System Status: Nominal.</p>
</div>
</footer>
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html lang="de" class="h-full bg-gray-900">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nexus Control Panel</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Custom Scrollbar für Nexus-Look */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #111827; }
::-webkit-scrollbar-thumb { background: #374151; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #4B5563; }
</style>
</head>
<body class="h-full text-gray-300 font-sans antialiased flex flex-col">
<nav class="bg-gray-800 border-b border-gray-700">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<div class="flex items-center">
<div class="flex-shrink-0 text-indigo-500 font-bold text-xl tracking-wider">
NEXUS
</div>
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-4">
<a href="/" class="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">Dashboard</a>
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">DHCP Leases</a>
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Logs</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<main class="flex-grow">
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">

View File

@@ -1,22 +1,59 @@
<?php
declare(strict_types=1);
use App\App;
function app(): App
{
return App::get();
}
function t(string $key, $default = '', array $vars = []): string
{
return app()->i18n()->get($key, $default, $vars);
}
/**
* Lädt ein Template-Partial.
*
* @param string $name Dateiname ohne .php
* @param string $folder Unterordner in /public/partials/
* @param string $folder Unterordner in /partials/
* @param array $data Daten, die im Template verfügbar sein sollen
*/
function tpl(string $name, string $folder = 'landing', array $data = []): void
{
$path = __DIR__ . '/../../public/partials/' . $folder . '/' . $name . '.php';
if (file_exists($path)) {
$base = __DIR__ . '/../../partials/';
foreach ([$name, $folder] as $value) {
if (preg_match('/[^a-zA-Z0-9_\-]/', $value)) {
echo "<!-- tpl(): invalid parameter -->";
return;
}
}
$paths = [];
if ($folder === 'landing') {
$paths[] = $base . 'landing/' . $name . '.php';
$paths[] = $base . 'landing/main/' . $name . '.php';
} else {
$paths[] = $base . 'structure/' . $name . '.php';
}
$path = null;
foreach ($paths as $candidate) {
if (file_exists($candidate)) {
$path = $candidate;
break;
}
}
if ($path === null) {
echo "<!-- Template not found: {$folder}/{$name} -->";
return;
}
extract($data);
require $path;
} else {
echo "<!-- Template not found: {$folder}/{$name} -->";
}
}
/**
@@ -26,3 +63,70 @@ function e(?string $string): string
{
return htmlspecialchars($string ?? '', ENT_QUOTES, 'UTF-8');
}
function app_primary_domain(): string
{
if (defined('APP_DOMAIN_PRIMARY')) {
return APP_DOMAIN_PRIMARY;
}
if (defined('APP_DOMAIN_NAME')) {
return APP_DOMAIN_NAME;
}
return $_SERVER['HTTP_HOST'] ?? '';
}
function app_fakecheck_domain(): string
{
if (defined('APP_DOMAIN_FAKECHECK')) {
return APP_DOMAIN_FAKECHECK;
}
return app_primary_domain();
}
function asset_styles(): void
{
$styles = app()->assets()->styles();
$order = ['early' => 0, 'normal' => 1, 'late' => 2];
usort($styles, fn($a, $b) => ($order[$a['priority']] ?? 1) <=> ($order[$b['priority']] ?? 1));
foreach ($styles as $s) {
$href = $s['href'];
$v = $s['version'];
if ($v !== null && $v !== '') {
$sep = (str_contains($href, '?') ? '&' : '?');
$href = $href . $sep . 'v=' . rawurlencode((string)$v);
}
echo '<link rel="stylesheet" href="' . htmlspecialchars($href, ENT_QUOTES) . '">' . "\n";
}
}
function asset_scripts(string $pos = 'footer'): void
{
$scripts = ($pos === 'header') ? app()->assets()->headerScripts() : app()->assets()->footerScripts();
foreach ($scripts as $s) {
$src = $s['src'];
$v = $s['version'];
if ($v !== null && $v !== '') {
$sep = (str_contains($src, '?') ? '&' : '?');
$src = $src . $sep . 'v=' . rawurlencode((string)$v);
}
$attrs = '';
if (!empty($s['defer'])) {
$attrs .= ' defer';
}
if (!empty($s['async'])) {
$attrs .= ' async';
}
echo '<script src="' . htmlspecialchars($src, ENT_QUOTES) . '"' . $attrs . '></script>' . "\n";
}
}
function redirect(string $path): void
{
header('Location: ' . $path, true, 303);
exit;
}

View File

@@ -1,103 +0,0 @@
<?php
declare(strict_types=1);
use App\App;
function app(): App
{
return App::get();
}
function t(string $key, $default = '', array $vars = []): string
{
return app()->i18n()->get($key, $default, $vars);
}
function tpl(string $file, string $type = 'structure', string $site = 'main'): void
{
$base = __DIR__ . '/../partials/';
// very small validation
foreach ([$file, $type, $site] as $v) {
if (preg_match('/[^a-zA-Z0-9_\-]/', $v)) {
echo "<!-- tpl(): invalid parameter -->";
return;
}
}
if ($type === 'landing') {
$path = $base . "landing/$site/$file.php";
} else {
$path = $base . "structure/$file.php";
}
if (file_exists($path)) {
include $path;
} else {
echo "<!-- tpl(): not found: $path -->";
}
}
function app_primary_domain(): string
{
if (defined('APP_DOMAIN_PRIMARY')) {
return APP_DOMAIN_PRIMARY;
}
if (defined('APP_DOMAIN_NAME')) {
return APP_DOMAIN_NAME;
}
return $_SERVER['HTTP_HOST'] ?? '';
}
function app_fakecheck_domain(): string
{
if (defined('APP_DOMAIN_FAKECHECK')) {
return APP_DOMAIN_FAKECHECK;
}
return app_primary_domain();
}
function asset_styles(): void
{
$styles = app()->assets()->styles();
// simple priority order
$order = ['early' => 0, 'normal' => 1, 'late' => 2];
usort($styles, fn($a,$b) => ($order[$a['priority']] ?? 1) <=> ($order[$b['priority']] ?? 1));
foreach ($styles as $s) {
$href = $s['href'];
$v = $s['version'];
if ($v !== null && $v !== '') {
$sep = (str_contains($href, '?') ? '&' : '?');
$href = $href . $sep . 'v=' . rawurlencode((string)$v);
}
echo '<link rel="stylesheet" href="' . htmlspecialchars($href, ENT_QUOTES) . '">' . "\n";
}
}
function asset_scripts(string $pos = 'footer'): void
{
$scripts = ($pos === 'header') ? app()->assets()->headerScripts() : app()->assets()->footerScripts();
foreach ($scripts as $s) {
$src = $s['src'];
$v = $s['version'];
if ($v !== null && $v !== '') {
$sep = (str_contains($src, '?') ? '&' : '?');
$src = $src . $sep . 'v=' . rawurlencode((string)$v);
}
$attrs = '';
if (!empty($s['defer'])) $attrs .= ' defer';
if (!empty($s['async'])) $attrs .= ' async';
echo '<script src="' . htmlspecialchars($src, ENT_QUOTES) . '"' . $attrs . '></script>' . "\n";
}
}
function redirect(string $path): void
{
header('Location: ' . $path, true, 303);
exit;
}