<?php
declare(strict_types=1);

// Router for PHP's built-in development server. The public directory is the
// document root: assets and uploads are served as files, everything else is
// handled by the PHP application (including client-side routes).
$publicRoot = realpath(__DIR__);
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$decodedPath = rawurldecode($requestPath);

// Reject malformed paths, traversal attempts, Windows separators and hidden
// files. Never allow direct access to PHP source through a public URL.
if (str_contains($decodedPath, "\0") || str_contains($decodedPath, '\\') ||
    preg_match('~(?:^|/)\.{1,2}(?:/|$)~', $decodedPath) ||
    preg_match('~(?:^|/)\.[^/]+~', $decodedPath)) {
    http_response_code(404);
    exit;
}

// Only protect private directories at URL root. `/assets/vendor/` contains
// the *public* React runtime and must remain accessible.
if (preg_match('~^/(?:storage|src|tests|\.git)(?:/|$)~i', $decodedPath)) {
    http_response_code(404);
    exit;
}

$target = realpath($publicRoot . '/' . ltrim($decodedPath, '/'));
if ($target !== false && is_file($target) &&
    str_starts_with($target, $publicRoot . DIRECTORY_SEPARATOR) &&
    !in_array(strtolower(pathinfo($target, PATHINFO_EXTENSION)), ['php', 'phtml', 'phar'], true)) {
    // PHP's built-in server serves public assets directly with correct MIME
    // types and cache/range handling when the router returns false.
    return false;
}

// Avoid silently rendering the storefront HTML for missing asset requests.
if (str_starts_with($decodedPath, '/assets/') || str_starts_with($decodedPath, '/uploads/')) {
    http_response_code(404);
    header('Content-Type: text/plain; charset=utf-8');
    echo 'File not found';
    exit;
}

require $publicRoot . '/index.php';
