Finanzmanager/src/Router.php
fds2610-bot b1712bb7ea Phase 0: Projektgerüst mit nginx, php-fpm und MariaDB
Docker Compose mit drei Services (nginx auf Port 8000), Migrationsmechanik,
Update- und Backup-Skript. Anwendung: Router mit CSRF-Prüfung, Anmeldung und
Ersteinrichtung, zentraler Einstellungsdialog mit Reitern, ein- und
ausschaltbares Debug-Log mit Maskierung von Zugangsdaten.

Layout nach Vorbild des FinanzManagers: feste Navigation links,
Werkzeugleiste oben, Tab-Leiste; Farbschema hell/dunkel/System.

Tests: 51 PHP-Prüfungen und 7 Playwright-Tests, alle grün.
2026-08-09 20:21:42 +02:00

76 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
namespace Finanzmanager;
class Router
{
private array $routen = [];
public function add(string $methode, string $muster, callable $handler): void
{
$this->routen[] = [
'methode' => strtoupper($methode),
'muster' => $muster,
'handler' => $handler,
];
}
public function get(string $muster, callable $handler): void
{
$this->add('GET', $muster, $handler);
}
public function post(string $muster, callable $handler): void
{
$this->add('POST', $muster, $handler);
}
public function dispatch(): void
{
$methode = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
// Formulare können die Methode über ein verstecktes Feld überschreiben.
if ($methode === 'POST') {
$override = $_POST['_method'] ?? $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? null;
if ($override) {
$methode = strtoupper((string)$override);
}
}
$pfad = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$pfad = '/' . trim($pfad, '/');
// Jeder verändernde Request braucht ein gültiges CSRF-Token.
if (in_array($methode, ['POST', 'PUT', 'DELETE', 'PATCH'], true)) {
Auth::pruefeCsrfToken((string)($_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''));
}
foreach ($this->routen as $route) {
if ($route['methode'] !== $methode) {
continue;
}
$params = self::passt($route['muster'], $pfad);
if ($params !== null) {
($route['handler'])($params);
return;
}
}
http_response_code(404);
(new View())->render('layout/404.php', ['pfad' => $pfad]);
}
/** Übersetzt `/konten/{id}` in einen regulären Ausdruck mit benannten Gruppen. */
public static function passt(string $muster, string $pfad): ?array
{
$regex = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $muster);
if (preg_match('#^' . $regex . '$#', $pfad, $treffer)) {
return array_filter($treffer, 'is_string', ARRAY_FILTER_USE_KEY);
}
return null;
}
}