monitor/api/src/Http/Request.php
fds2610-bot 857fc88834 Phase 1 der Neuausrichtung: REST-API fuer Tickets/Events/Systeme/KPIs/Agenten
Setzt Phase 1 aus Visualization.md um: Vanilla-PHP-REST-API mit SQLite-Persistenz,
statischen API-Keys pro Agent, Codeberg-Sync fuer Backlog/Done, PHPUnit-Tests und
vollstaendiger API.md-Dokumentation - Vorgaben aus Detailantworten.md (F1-F16)
umgesetzt. Entwicklung/Build/Test laufen komplett in Docker-Compose-Containern
(PHP 8.2 + SQLite + Composer + PHPUnit/pcov), analog zum NC-Gantt-Projekt ist auf
dem Host kein PHP/Composer noetig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:38:52 +02:00

68 lines
2 KiB
PHP

<?php
declare(strict_types=1);
namespace Monitor\Api\Http;
final class Request
{
/** @param array<string, string> $headers */
private function __construct(
public readonly string $method,
public readonly string $path,
public readonly array $query,
public readonly array $body,
private readonly array $headers,
) {
}
public static function fromGlobals(): self
{
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$path = rtrim((string) parse_url($uri, PHP_URL_PATH), '/');
if ($path === '') {
$path = '/';
}
parse_str((string) (parse_url($uri, PHP_URL_QUERY) ?? ''), $query);
$rawBody = file_get_contents('php://input') ?: '';
$body = [];
if ($rawBody !== '') {
$decoded = json_decode($rawBody, true);
if (is_array($decoded)) {
$body = $decoded;
}
}
$headers = [];
foreach ($_SERVER as $key => $value) {
if (str_starts_with($key, 'HTTP_')) {
$name = str_replace('_', '-', strtolower(substr($key, 5)));
$headers[$name] = (string) $value;
}
}
if (isset($_SERVER['CONTENT_TYPE'])) {
$headers['content-type'] = (string) $_SERVER['CONTENT_TYPE'];
}
return new self($method, $path, $query, $body, $headers);
}
/** @param array<string, mixed> $body */
public static function create(string $method, string $path, array $query = [], array $body = [], array $headers = []): self
{
$normalized = [];
foreach ($headers as $name => $value) {
$normalized[strtolower($name)] = $value;
}
return new self($method, rtrim($path, '/') ?: '/', $query, $body, $normalized);
}
public function header(string $name): ?string
{
return $this->headers[strtolower($name)] ?? null;
}
}