Backup: old custom PHP API code removed from fahrschultermin.de

This commit is contained in:
Hermes Agent
2026-05-20 16:36:12 +02:00
parent 8ab4e532fd
commit 8fccf0e406
59 changed files with 5146 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Support;
use App\Repositories\UserRepository;
final class Auth
{
public static function user(): ?array
{
$userId = $_SESSION['user_id'] ?? null;
if (!$userId) {
return null;
}
return (new UserRepository())->findById((int) $userId);
}
public static function requireUser(): array
{
$user = self::user();
if ($user === null) {
Response::json(['message' => 'Unauthenticated'], 401);
}
return $user;
}
public static function requireRole(array|string $roles): array
{
$user = self::requireUser();
$roles = (array) $roles;
if (!in_array($user['role'], $roles, true)) {
Response::json(['message' => 'Forbidden'], 403);
}
return $user;
}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Support;
use PDO;
use PDOException;
final class Database
{
private static ?PDO $connection = null;
private static array $config = [];
public static function configure(array $config): void
{
self::$config = $config;
self::$connection = null; // reset on reconfigure
}
public static function connection(): PDO
{
if (self::$connection instanceof PDO) {
return self::$connection;
}
$driver = self::$config['db_driver'] ?? 'sqlite';
if ($driver === 'pgsql') {
$host = self::$config['db_host'] ?? '127.0.0.1';
$port = self::$config['db_port'] ?? '5432';
$dbname = self::$config['db_database'] ?? '';
$user = self::$config['db_username'] ?? '';
$password = self::$config['db_password'] ?? '';
$dsn = "pgsql:host={$host};port={$port};dbname={$dbname}";
self::$connection = new PDO($dsn, $user, $password);
} else {
$path = self::$config['db_path'] ?? self::$config['db_path'] ?? '';
$directory = dirname($path);
if (!is_dir($directory)) {
mkdir($directory, 0775, true);
}
self::$connection = new PDO('sqlite:' . $path);
self::$connection->exec('PRAGMA foreign_keys = ON');
}
self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return self::$connection;
}
public static function isPostgres(): bool
{
return (self::$config['db_driver'] ?? 'sqlite') === 'pgsql';
}
public static function lastInsertId(): string
{
if (self::isPostgres()) {
return self::$connection->query('SELECT lastval()')->fetchColumn();
}
return self::$connection->lastInsertId();
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Support;
final class Request
{
public function method(): string
{
return strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
}
public function path(): string
{
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$path = parse_url($uri, PHP_URL_PATH) ?: '/';
return rtrim($path, '/') ?: '/';
}
public function query(string $key, mixed $default = null): mixed
{
return $_GET[$key] ?? $default;
}
public function input(): array
{
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (str_contains($contentType, 'application/json')) {
$raw = file_get_contents('php://input');
$decoded = json_decode($raw ?: '[]', true);
return is_array($decoded) ? $decoded : [];
}
return $_POST;
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace App\Support;
final class Response
{
public static function json(array $data, int $status = 200): never
{
http_response_code($status);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
exit;
}
public static function noContent(): never
{
http_response_code(204);
exit;
}
}

View File

@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace App\Support;
final class Router
{
private array $routes = [];
public function __construct(private readonly Request $request)
{
}
public function get(string $path, callable $handler): void
{
$this->map('GET', $path, $handler);
}
public function post(string $path, callable $handler): void
{
$this->map('POST', $path, $handler);
}
public function patch(string $path, callable $handler): void
{
$this->map('PATCH', $path, $handler);
}
public function delete(string $path, callable $handler): void
{
$this->map('DELETE', $path, $handler);
}
public function dispatch(): void
{
$method = $this->request->method();
$path = $this->request->path();
foreach ($this->routes[$method] ?? [] as $route) {
$pattern = preg_replace('#\{([a-zA-Z_][a-zA-Z0-9_]*)\}#', '(?P<$1>[^/]+)', $route['path']);
$pattern = '#^' . $pattern . '$#';
if (!preg_match($pattern, $path, $matches)) {
continue;
}
$params = array_filter($matches, static fn (string|int $key): bool => is_string($key), ARRAY_FILTER_USE_KEY);
$route['handler']($this->request, $params);
return;
}
Response::json(['message' => 'Route not found', 'path' => $path], 404);
}
private function map(string $method, string $path, callable $handler): void
{
$this->routes[$method][] = [
'path' => rtrim($path, '/') ?: '/',
'handler' => $handler,
];
}
}