diff --git a/server/.htaccess b/server/.htaccess
index 9a66488..403e897 100644
--- a/server/.htaccess
+++ b/server/.htaccess
@@ -1,28 +1,15 @@
RewriteEngine On
RewriteBase /PS_Launcher/
-# HTTPS forcé
+# HTTPS forcé (si le mutualisé OVH ne le force pas déjà)
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Pas de listing de répertoires
Options -Indexes
-# /PS_Launcher/api/* → api/index.php (le PATH_INFO est exposé via QUERY_STRING)
-RewriteRule ^api/?$ api/index.php [QSA,L]
-RewriteRule ^api/(.*)$ api/index.php/$1 [QSA,L]
-
-# Bloquer l'accès direct aux fichiers sensibles
-
- Require all denied
-
-
-# Headers de sécurité
-
- Header set X-Content-Type-Options "nosniff"
- Header set X-Frame-Options "DENY"
- Header set Referrer-Policy "no-referrer"
-
-
-# Type MIME pour les ZIPs (assure la pris en compte de Range:)
-AddType application/zip .zip
+# /PS_Launcher/api -> api/index.php
+# /PS_Launcher/api/foo -> api/index.php?route=foo
+# (passage par query string : pas de PATH_INFO, marche partout)
+RewriteRule ^api/?$ api/index.php [QSA,L]
+RewriteRule ^api/([^?]+)/?$ api/index.php?route=$1 [QSA,L]
diff --git a/server/api/index.php b/server/api/index.php
index 16b40ec..2b62eb1 100644
--- a/server/api/index.php
+++ b/server/api/index.php
@@ -1,52 +1,77 @@
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 (hors git ; copier config.example.php → config.php au déploiement)
+// Charge la config (config.example.php est le template ; config.php est gitignored)
$configPath = __DIR__ . '/config.php';
if (!is_file($configPath)) {
- http_response_code(500);
- header('Content-Type: application/json; charset=utf-8');
- echo json_encode(['error' => 'config_missing', 'message' => 'config.php absent — copier config.example.php']);
- exit;
+ Response::error('config_missing', 'config.php absent — copier config.example.php', 500);
}
$config = require $configPath;
-// Le path est passé via REQUEST_URI parce que le RewriteRule utilise PATH_INFO
-$uri = $_SERVER['REQUEST_URI'] ?? '/';
-$path = parse_url($uri, PHP_URL_PATH) ?? '/';
-
-// Strip prefix /PS_Launcher/api
-if (preg_match('#^.*?/PS_Launcher/api(.*)$#', $path, $m)) {
- $route = trim($m[1], '/');
-} else {
- $route = trim($path, '/');
-}
-
+// La route est passée via ?route=... par le .htaccess
+$route = trim((string)($_GET['route'] ?? ''), '/');
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
-try {
- if ($method === 'GET' && ($route === '' || $route === 'manifest')) {
- require __DIR__ . '/routes/Manifest.php';
- \PSLauncher\Routes\Manifest::handle($config);
- return;
- }
-
- if ($method === 'GET' && preg_match('#^releasenotes/([0-9]+\.[0-9]+\.[0-9]+)$#', $route, $m)) {
- require __DIR__ . '/routes/Releasenotes.php';
- \PSLauncher\Routes\Releasenotes::handle($m[1]);
- return;
- }
-
- if ($method === 'GET' && $route === 'health') {
- Response::json(['status' => 'ok', 'serverTime' => gmdate('c')]);
- }
-
- Response::error('not_found', "Route not found: {$route}", 404);
-} catch (\Throwable $e) {
- error_log('[PSLauncher] ' . $e->getMessage() . "\n" . $e->getTraceAsString());
- Response::error('server_error', 'Internal server error', 500);
+if ($method === 'GET' && ($route === '' || $route === 'manifest')) {
+ require __DIR__ . '/routes/Manifest.php';
+ \PSLauncher\Routes\Manifest::handle($config);
+ return;
}
+
+if ($method === 'GET' && preg_match('#^releasenotes/([0-9]+\.[0-9]+\.[0-9]+)$#', $route, $m)) {
+ require __DIR__ . '/routes/Releasenotes.php';
+ \PSLauncher\Routes\Releasenotes::handle($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);