getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine()); echo json_encode([ 'error' => 'server_error', 'message' => $e->getMessage(), 'file' => basename($e->getFile()), 'line' => $e->getLine(), ]); exit; }); require __DIR__ . '/lib/Response.php'; use PSLauncher\Response; // Charge la config (config.example.php est le template ; config.php est gitignored) $configPath = __DIR__ . '/config.php'; if (!is_file($configPath)) { Response::error('config_missing', 'config.php absent — copier config.example.php', 500); } $config = require $configPath; // La route est passée via ?route=... par le .htaccess $route = trim((string)($_GET['route'] ?? ''), '/'); $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; if ($method === 'GET' && ($route === '' || $route === 'manifest')) { // Crypto requis : depuis v0.27.0 le manifest est re-signé à la volée // selon le channel demandé (filtrage server-side). require __DIR__ . '/lib/Crypto.php'; require __DIR__ . '/routes/Manifest.php'; \PSLauncher\Routes\Manifest::handle($config); return; } // Release notes : accepte 'X.Y.Z' (legacy) ou id stable 'v' + 8 hex (v0.27.1+) if ($method === 'GET' && preg_match('#^releasenotes/(v[0-9a-f]{8}|[0-9]+\.[0-9]+\.[0-9]+)$#', $route, $m)) { require __DIR__ . '/routes/Releasenotes.php'; \PSLauncher\Routes\Releasenotes::handle($m[1]); return; } if ($method === 'POST' && $route === 'license/validate') { require __DIR__ . '/lib/Db.php'; require __DIR__ . '/lib/Crypto.php'; require __DIR__ . '/routes/ValidateLicense.php'; \PSLauncher\Routes\ValidateLicense::handle($config); return; } if ($method === 'GET' && preg_match('#^download-url/([0-9]+\.[0-9]+\.[0-9]+)$#', $route, $m)) { require __DIR__ . '/lib/Db.php'; require __DIR__ . '/lib/Crypto.php'; require __DIR__ . '/routes/DownloadUrl.php'; \PSLauncher\Routes\DownloadUrl::handle($config, $m[1]); return; } if ($method === 'GET' && $route === 'health') { Response::json([ 'status' => 'ok', 'serverTime' => gmdate('c'), 'phpVersion' => PHP_VERSION, 'configLoaded' => is_array($config), ]); } if ($method === 'GET' && $route === 'debug') { Response::json([ 'status' => 'ok', 'route' => $route, 'request_uri' => $_SERVER['REQUEST_URI'] ?? '', 'script_name' => $_SERVER['SCRIPT_NAME'] ?? '', 'php' => PHP_VERSION, 'sodium' => function_exists('sodium_crypto_sign_detached'), 'pdo_mysql' => extension_loaded('pdo_mysql'), 'manifest_file' => is_file(dirname(__DIR__) . '/manifest/versions.json'), ]); } Response::error('not_found', "Route not found: '{$route}'", 404);