89 lines
2.5 KiB
PHP
89 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Steuerkram;
|
|
|
|
use Steuerkram\Auth;
|
|
|
|
class Router
|
|
{
|
|
private array $routes = [];
|
|
|
|
public function add(string $method, string $pattern, callable $handler): void
|
|
{
|
|
$this->routes[] = [
|
|
'method' => strtoupper($method),
|
|
'pattern' => $pattern,
|
|
'handler' => $handler,
|
|
];
|
|
}
|
|
|
|
public function get(string $pattern, callable $handler): void
|
|
{
|
|
$this->add('GET', $pattern, $handler);
|
|
}
|
|
|
|
public function post(string $pattern, callable $handler): void
|
|
{
|
|
$this->add('POST', $pattern, $handler);
|
|
}
|
|
|
|
public function put(string $pattern, callable $handler): void
|
|
{
|
|
$this->add('PUT', $pattern, $handler);
|
|
}
|
|
|
|
public function delete(string $pattern, callable $handler): void
|
|
{
|
|
$this->add('DELETE', $pattern, $handler);
|
|
}
|
|
|
|
public function dispatch(): void
|
|
{
|
|
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
|
// Support method override via hidden _method field or X-HTTP-Method-Override header
|
|
if ($method === 'POST') {
|
|
$override = $_POST['_method'] ?? $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? null;
|
|
if ($override) {
|
|
$method = strtoupper($override);
|
|
}
|
|
}
|
|
|
|
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
|
|
$uri = '/' . trim($uri, '/');
|
|
if ($uri === '') $uri = '/';
|
|
|
|
if (in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'], true)) {
|
|
$token = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
|
|
Auth::validateCsrfToken($token);
|
|
}
|
|
|
|
foreach ($this->routes as $route) {
|
|
if ($route['method'] !== $method) continue;
|
|
|
|
$params = $this->match($route['pattern'], $uri);
|
|
if ($params !== null) {
|
|
($route['handler'])($params);
|
|
return;
|
|
}
|
|
}
|
|
|
|
http_response_code(404);
|
|
$view = new View();
|
|
$view->render('layout/404.php', ['uri' => $uri]);
|
|
}
|
|
|
|
private function match(string $pattern, string $uri): ?array
|
|
{
|
|
// Convert route pattern to regex: {id} → named capture
|
|
$regex = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $pattern);
|
|
$regex = '#^' . $regex . '$#';
|
|
|
|
if (preg_match($regex, $uri, $matches)) {
|
|
return array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|