weitere Bearibeitung

This commit is contained in:
2026-06-17 16:45:14 +02:00
parent 06645f1e9c
commit 1891ec0a51
38 changed files with 2720 additions and 109 deletions
+6
View File
@@ -1,7 +1,13 @@
RewriteEngine On
# Proxy-Unterstützung: X-Forwarded-* Header durchreichen
RewriteCond %{HTTP:X-Forwarded-Proto} ^https$
RewriteRule ^ - [E=HTTPS:on]
# Statische Dateien direkt ausliefern
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Alle anderen Anfragen an index.php weiterleiten
RewriteRule ^ index.php [QSA,L]
+19
View File
@@ -383,6 +383,25 @@ th {
border: 1px solid rgba(143, 69, 24, 0.16);
}
.alert {
margin-bottom: 1rem;
padding: 1rem 1.2rem;
border-radius: 1rem;
font-weight: 700;
}
.alert-info {
background: rgba(18, 79, 71, 0.08);
border: 1px solid rgba(18, 79, 71, 0.16);
color: var(--secondary);
}
.alert-error {
background: var(--danger);
border: 1px solid rgba(143, 69, 24, 0.16);
color: var(--primary-strong);
}
.code-block {
overflow: auto;
padding: 1rem;
+160
View File
@@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
use App\Controllers\PlatformController;
use App\Controllers\TenantController;
use App\Core\Response;
use App\Services\SecurityHeadersService;
/**
* Test-Index lädt bootstrap_test.php (SQLite) statt bootstrap.php (MySQL).
* Gleicher Routing-Code wie index.php.
*/
$app = require dirname(__DIR__) . '/app/bootstrap_test.php';
(new SecurityHeadersService())->send();
$database = $app['database'];
$config = $app['config'];
$platform = new PlatformController(
$app['rootPath'],
$config,
$database,
$app['view'],
$app['session'],
$app['csrf']
);
$tenantController = new TenantController(
$database,
$app['view'],
$app['session'],
$app['csrf'],
$config
);
$path = current_path();
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
try {
if ($path === '/' && $method === 'GET') {
$platform->home();
return;
}
if ($path === '/install') {
$method === 'POST' ? $platform->installSubmit() : $platform->installForm();
return;
}
if ($path === '/register') {
$method === 'POST' ? $platform->registerSubmit() : $platform->registerForm();
return;
}
if ($path === '/admin/login') {
$method === 'POST' ? $platform->adminLoginSubmit() : $platform->adminLoginForm();
return;
}
if ($path === '/password/forgot') {
$method === 'POST' ? $platform->passwordResetRequestSubmit() : $platform->passwordResetRequestForm();
return;
}
if ($path === '/reset-password') {
$method === 'POST' ? $platform->passwordResetConfirmSubmit() : $platform->passwordResetConfirmForm();
return;
}
if ($path === '/admin' && $method === 'GET') {
$platform->adminDashboard();
return;
}
if ($path === '/admin/logout' && $method === 'POST') {
$platform->adminLogout();
return;
}
if ($path === '/api/rfid/intake' && $method === 'POST') {
if (!($config['rfid_ingest_enabled'] ?? false)) {
Response::notFound();
return;
}
$tenantController->rfidIngest();
return;
}
if (preg_match('#^/t/([^/]+)(?:/(.*))?$#', $path, $matches)) {
$tenantSlug = rawurldecode($matches[1]);
$subPath = trim((string) ($matches[2] ?? ''), '/');
if ($subPath === '' && $method === 'GET') {
$tenantController->dashboard($tenantSlug);
return;
}
if ($subPath === 'login') {
$method === 'POST' ? $tenantController->loginSubmit($tenantSlug) : $tenantController->loginForm($tenantSlug);
return;
}
if ($subPath === 'logout' && $method === 'POST') {
$tenantController->logout($tenantSlug);
return;
}
if ($subPath === 'members') {
$tenantController->members($tenantSlug);
return;
}
if ($subPath === 'products') {
$tenantController->products($tenantSlug);
return;
}
if ($subPath === 'bookings') {
$tenantController->bookings($tenantSlug);
return;
}
if ($subPath === 'exports/balances.csv' && $method === 'GET') {
$tenantController->exportBalances($tenantSlug);
return;
}
if ($subPath === 'exports/bookings.csv' && $method === 'GET') {
$tenantController->exportBookings($tenantSlug);
return;
}
if ($subPath === 'payments') {
$tenantController->payments($tenantSlug);
return;
}
if ($subPath === 'paper-sheets') {
$tenantController->paperSheets($tenantSlug);
return;
}
if ($subPath === 'rfid') {
$tenantController->rfid($tenantSlug);
return;
}
}
Response::notFound();
} catch (\Throwable $throwable) {
http_response_code(500);
error_log($throwable->__toString());
echo '<h1>Fehler</h1>';
echo '<p>' . e($config['debug'] ? $throwable->getMessage() : 'Die Anfrage konnte gerade nicht verarbeitet werden.') . '</p>';
}
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* Router für die Test-/Entwicklungsumgebung mit Proxy-Support.
* Erkennt den code-server Proxy-Prefix (z.B. /proxy/8080 oder /absproxy/8080) und speichert ihn.
*
* Start: php -S 0.0.0.0:8080 public/router_test.php
*/
// Proxy-Prefix erkennen und speichern, dann aus REQUEST_URI entfernen
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$pathOnly = parse_url($requestUri, PHP_URL_PATH) ?: '/';
$proxyPrefix = '';
if (preg_match('#^(/(?:abs)?proxy/\d+)(/.*)?$#', $pathOnly, $matches)) {
$proxyPrefix = $matches[1];
$subPath = isset($matches[2]) && $matches[2] !== '' ? $matches[2] : '/';
// REQUEST_URI umschreiben für die Anwendung
$_SERVER['REQUEST_URI'] = $subPath;
}
// Proxy-Prefix global verfügbar machen für base_path()
$_SERVER['KAFFEEKASSE_PROXY_PREFIX'] = $proxyPrefix;
// Neu parsen nach Umschreibung
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$file = __DIR__ . ($path === '/' ? '/index.php' : (string) $path);
// Statische Dateien direkt ausliefern (CSS, JS, etc.)
if ($path !== '/' && is_file($file)) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
$mimeTypes = [
'css' => 'text/css; charset=UTF-8',
'js' => 'application/javascript; charset=UTF-8',
'png' => 'image/png',
'jpg' => 'image/jpeg',
'svg' => 'image/svg+xml',
'ico' => 'image/x-icon',
];
if (isset($mimeTypes[$ext])) {
header('Content-Type: ' . $mimeTypes[$ext]);
}
return false;
}
require __DIR__ . '/index_test.php';