Routage

OxPHP achemine les requêtes HTTP entrantes selon l'un des trois modes, contrôlé par une seule variable d'environnement. Chaque mode reflète une configuration nginx try_files familière, ce qui vous permet de prédire exactement ce qui se passe pour n'importe quelle URL.

Fonctionnement

Chaque requête passe par un pipeline partagé avant que la logique propre au mode n'entre en jeu :

  1. Filtre des chemins cachés — les chemins contenant des segments masqués (.git, .env) sont bloqués, avec une exception pour /.well-known/* (RFC 8615)
  2. Consultation du cache de routes — les URI récemment résolues sont renvoyées depuis un cache LRU (10 000 entrées)
  3. Décodage des pourcentages + assainissement — les séquences encodées comme %2e%2e sont décodées et les segments de traversée (.., ., vides) sont supprimés
  4. Blocage PHP well-known — défense en profondeur : les scripts .php situés dans /.well-known/ ne s'exécutent jamais
  5. Classification des URI — le chemin assaini est classé une seule fois en NoExtension, Php ou OtherExtension
  6. Répartition selon le mode — chaque mode gère les trois types d'URI avec ses propres règles
  7. Validation des liens symboliques — chaque chemin de système de fichiers résolu doit se canonicaliser à l'intérieur de la racine du document

L'étape de classification est la clé de l'efficacité : la vérification sur disque des fichiers statiques (/style.css, /logo.png) est effectuée une seule fois dans la couche partagée pour les URI OtherExtension, de sorte que les trois modes paient le même coût.

Configuration

Variable Défaut Description
DOCUMENT_ROOT /var/www/html/public Répertoire racine pour servir les fichiers et les scripts PHP
ENTRY_FILE (non défini) Script d'entrée canonique unique. Non défini = Traditionnel. *.php = Framework. Non-.php = SPA. Avec WORKER_MODE_ENABLED=true = Worker. Accepte un chemin absolu ou relatif à DOCUMENT_ROOT (.. autorisé) ; le chemin résolu doit exister
WORKER_MODE_ENABLED false Active le mode worker persistant. Nécessite que ENTRY_FILE pointe vers un script .php

Les anciennes variables INDEX_FILE et WORKER_FILE sont toujours analysées (avec un WARN au démarrage) et se rattachent au nouveau modèle. Voir Configuration → Déprécié.

Modes de routage

Les modes Traditionnel, Framework et SPA sont sélectionnés par ENTRY_FILE lorsque WORKER_MODE_ENABLED=false, et chacun correspond à une configuration nginx try_files équivalente.

Actif lorsque ENTRY_FILE n'est pas défini (ou vide) et que WORKER_MODE_ENABLED=false. Configuration nginx équivalente :

nginx
location / { try_files $uri $uri/ /index.php /index.html =404; } location ~ \.php$ { try_files $uri =404; # PATH_INFO splitting enabled }

Ordre de résolution :

  1. $uri — fichier exact sur le disque → servi (ou exécuté si .php)
  2. $uri/ — répertoire → recherche de index.php, puis de index.html à l'intérieur
  3. Découpage PATH_INFO — lorsque l'URI contient .php/, le préfixe du script est mis en correspondance sur le disque et le reste devient PATH_INFO (par ex. /api.php/users/42 → script api.php, PATH_INFO=/users/42)
  4. /index.php — repli sur le contrôleur frontal racine
  5. /index.html — repli sur l'index statique racine
  6. 404

Exemples :

Requête Résultat
/about.php Exécute about.php
/style.css Sert style.css
/blog/ (avec blog/index.php) Exécute blog/index.php
/api.php/users/42 Exécute api.php avec PATH_INFO=/users/42
/missing.txt Repli sur /index.php
/some/route Repli sur /index.php

Le découpage PATH_INFO est toujours actif en mode Traditionnel. Il n'existe pas de bascule d'environnement — l'ancien indicateur SPLIT_PATH_INFO_ENABLED a été supprimé.

Mode worker

Le mode worker s'active lorsque WORKER_MODE_ENABLED=true et que ENTRY_FILE pointe vers un script .php. Le routeur sert les fichiers statiques depuis le disque et achemine toutes les autres requêtes vers l'ENTRY_FILE du worker — le worker est l'unique contrôleur frontal.

Type d'URI Comportement
Fichiers statiques (.css, .png, … — toute extension non-.php) Servis directement depuis le disque s'ils sont présents ; un fichier manquant se replie sur l'ENTRY_FILE du worker (pas de 404 définitif)
Tout le reste (URI .php, chemins sans extension, /) Acheminé vers l'ENTRY_FILE du worker

Les fichiers .php arbitraires dans la racine du document ne sont jamais exécutés directement en mode worker — une requête vers /about.php atteint le callback du worker comme n'importe quelle autre route, même si about.php existe sur le disque. Il n'y a ni recherche d'index de répertoire, ni repli sur un index.php racine ; le worker voit lui-même ces requêtes.

Deux exceptions, toutes deux des défenses au niveau du serveur qui s'exécutent avant la répartition selon le mode : les chemins dont un segment commence par un point (/.git/config, /.env, /.well-known seul) sont rejetés par le blocage des chemins cachés, et les URI .php sous /.well-known/ sont refusées par défense en profondeur. Les deux renvoient un 404 et n'atteignent jamais le worker.

La validation au démarrage rejette deux combinaisons :

  • WORKER_MODE_ENABLED=true sans ENTRY_FILEWORKER_MODE_ENABLED=true requires ENTRY_FILE to be set.
  • WORKER_MODE_ENABLED=true avec un ENTRY_FILE non-.phpWORKER_MODE_ENABLED=true requires a .php ENTRY_FILE.

Voir Mode worker pour tous les détails de configuration.

Comportement de PATH_INFO

$_SERVER['PATH_INFO'] est renseigné différemment selon le mode :

Mode Quand il est défini Valeur
Traditionnel Uniquement lorsque l'URI contient .php/ (découpage PATH_INFO) Ce qui suit le segment du script, par ex. /users/42
Framework Uniquement pour une requête explicite /index.php/extra Ce qui suit le fichier d'entrée, par ex. /news
SPA Jamais (PHP n'est invoqué que pour les fichiers .php exacts ; pas de PATH_INFO)

PATH_INFO suit la sémantique CGI : il n'est présent que lorsque SCRIPT_NAME (le script exécuté) est un préfixe littéral du chemin de la requête. Une réécriture vers le contrôleur frontal que l'URL ne nomme pas — une route applicative, un index de répertoire, un repli sur fichier statique manquant — ne porte aucun PATH_INFO ; lisez plutôt REQUEST_URI. En mode Traditionnel, l'ancienne variable d'environnement SPLIT_PATH_INFO_ENABLED a été supprimée.

Sécurité des chemins

OxPHP applique plusieurs couches de protection pour empêcher la traversée de répertoires, la divulgation de fichiers cachés et les attaques par évasion de lien symbolique :

  • Le décodage des pourcentages s'exécute avant l'assainissement, de sorte que les tentatives de traversée encodées comme /%2e%2e/etc/passwd sont interceptées
  • Le filtrage des segments supprime les segments .., . et vides du chemin résolu
  • La validation des liens symboliques canonicalise chaque chemin résolu et vérifie qu'il reste à l'intérieur de la racine du document. Les liens symboliques qui pointent en dehors du répertoire servi sont bloqués
  • Le blocage des chemins cachés bloque tout segment de chemin commençant par . (par ex. /.git/config, /.env), avec une exception pour /.well-known/* conformément à la RFC 8615
  • Blocage PHP well-known — même avec l'exception des chemins cachés, les scripts .php sous /.well-known/ ne sont jamais exécutés (défense en profondeur)
  • Liste de refus d'exécution PHP — dans les modes à mappage direct (Traditionnel et SPA), PHP_DENY_PATHS bloque l'exécution .php selon des motifs glob configurés (par ex. /uploads/**, ou un fichier unique comme /admin/legacy.php) avant toute E/S disque. Voir Liste de refus d'exécution PHP
Note

Si le répertoire de la racine du document n'existe pas au démarrage, le serveur se termine avec une erreur fatale. La protection contre l'évasion de lien symbolique nécessite un chemin de racine du document valide et résolvable.

Dépannage

Toutes les requêtes renvoient un 404 en mode Traditionnel

Vérifiez que index.php ou index.html existe à la racine du document. La chaîne try_files du mode Traditionnel ne se replie que sur ces fichiers — si les deux sont absents et qu'aucun fichier ne correspond à l'URL, vous obtenez un 404.

bash
docker exec <container> ls /var/www/html/public
Un fichier statique manquant renvoie un 404 au lieu de la coquille SPA

C'est intentionnel en mode SPA : un /style.css manquant donne un 404 définitif, et non un repli silencieux vers index.html, ce qui détecte tôt les références de fichiers cassées. Dans les modes Framework et Traditionnel, un fichier statique manquant se replie sur le contrôleur frontal (/index.php), de sorte que le routeur de votre application rend le 404. Utilisez le mode SPA si vous voulez des 404 définitifs sur les fichiers manquants.

/index.php direct ne renvoie plus de 404

En mode Framework, l'accès direct au contrôleur frontal est désormais autorisé (la réécriture vers /index.php est idempotente). Si vous vous appuyiez auparavant sur le 404 pour détecter les accès directs, passez à la vérification de REQUEST_URI depuis l'intérieur du contrôleur.

PATH_INFO est vide en mode Framework

C'est le comportement attendu pour les routes applicatives. Le mode Framework suit la sémantique CGI : PATH_INFO n'est défini que lorsque la requête nomme explicitement le fichier d'entrée avec un segment final (/index.php/news/news). Pour une route applicative normale comme /users/42, le contrôleur frontal est atteint par une réécriture interne qu'elle ne nomme pas, donc PATH_INFO est absent — lisez le chemin depuis $_SERVER['REQUEST_URI']. (Si ENTRY_FILE ne se termine pas par .php, OxPHP choisit le mode SPA, qui ne renseigne jamais PATH_INFO.)

Un lien symbolique dans la racine du document renvoie un 404

Les liens symboliques qui pointent en dehors de la racine du document sont bloqués par conception. Déplacez le contenu cible à l'intérieur de la racine du document, ou montez-le comme un répertoire au bon emplacement.

Exemple Docker

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" volumes: - ./src:/var/www/html environment: - DOCUMENT_ROOT=/var/www/html/public - ENTRY_FILE=index.php

Voir aussi