Une redirection côté serveur semble simple, mais en PHP elle touche vite au cache, au comportement du navigateur et à la sécurité. Je la traite toujours comme un contrat HTTP, pas comme un simple changement d’URL. Dans cet article, je détaille la logique de php redirect, le choix du bon code, la mise en place propre en PHP et les erreurs qui cassent le plus souvent les déploiements.
Les points essentiels à garder en tête avant d’écrire une redirection
- Une redirection PHP envoie une réponse HTTP avec l’en-tête `Location`, puis le client demande la nouvelle URL.
- Le code de statut compte autant que l’URL : 301 et 308 servent aux migrations permanentes, 302 et 307 aux changements temporaires, 303 après un POST.
- `header('Location:')` seul vaut 302 dans PHP, donc il faut souvent fixer explicitement le statut.
- Aucun contenu ne doit sortir avant les en-têtes, sinon la redirection peut échouer ou devenir imprévisible.
- Ne laisse jamais l’utilisateur fournir une URL brute sans contrôle, sinon tu ouvres la porte aux redirections malveillantes.
- Dans une API, le choix du code change le contrat : préserver ou non la méthode HTTP n’a pas le même impact selon le cas d’usage.
Ce que fait réellement une redirection PHP
Dans une application backend, une redirection n’est pas un artifice visuel. Le serveur répond avec un statut 3xx et un en-tête Location, puis le client suit automatiquement la nouvelle adresse. C’est ce mécanisme qui permet de migrer une route, de renvoyer un utilisateur après authentification ou de canoniser une URL sans bricolage côté navigateur.
Je distingue toujours trois familles de cas. La redirection HTTP sert à transférer proprement la requête vers une autre ressource. La réécriture interne, elle, garde l’URL visible inchangée dans la barre d’adresse. Enfin, une redirection JavaScript ou via reste un plan B, utile seulement quand on ne contrôle plus le serveur. Pour du backend et des API, le serveur doit rester l’autorité, pas le client.
En pratique, la plupart des besoins se ressemblent : changement de nom de page, migration de domaine, page de maintenance, flux de connexion, ou ancien endpoint qu’on ne veut plus servir directement. L’intérêt d’une vraie redirection HTTP, c’est qu’elle parle à la fois aux navigateurs, aux robots et aux clients techniques. Le point décisif, ensuite, est de choisir le bon code de statut pour que tous interprètent la transition de la même façon.

Choisir le bon code HTTP pour ne pas brouiller le signal
Le choix du statut est souvent ce qui différencie une redirection propre d’un raccourci fragile. La documentation PHP rappelle d’ailleurs que header('Location:') renvoie par défaut un 302 si aucun code n’est précisé. C’est pratique pour tester vite, mais insuffisant dès qu’il y a un vrai enjeu de cache, de méthode HTTP ou de référencement.
| Code | Usage courant | Comportement de la méthode | Quand je le choisis |
|---|---|---|---|
| 301 | Redirection permanente | La méthode peut être modifiée par certains clients | Migration définitive d’une URL, changement de structure, canonicalisation |
| 302 | Redirection temporaire | La méthode peut être modifiée par certains clients | Test, bascule temporaire, page indisponible pour un court moment |
| 303 | Voir autre chose après un envoi de formulaire | La requête suivante devient un GET
|
Pattern POST-Redirect-GET, page de confirmation après soumission |
| 307 | Redirection temporaire stricte | La méthode et le corps sont conservés | API ou parcours où il faut garder exactement la requête d’origine |
| 308 | Redirection permanente stricte | La méthode et le corps sont conservés | Migration permanente d’un endpoint non-GET sans changer le verbe |
Pour résumer simplement : 301 et 308 servent à dire “c’est déplacé pour de bon”, tandis que 302 et 307 disent “c’est temporaire”. La différence entre 301/302 d’un côté et 307/308 de l’autre tient surtout à la conservation de la méthode. MDN souligne précisément que 303 force un retour en GET, ce qui est idéal après un POST quand on veut éviter un renvoi accidentel du formulaire au rafraîchissement.
En migration SEO, j’utilise plutôt 301 quand l’URL cible est stable et durable. En API, je préfère 307 ou 308 si le client doit conserver le verbe et le corps, par exemple sur une opération POST ou PUT. Une fois le code choisi, il reste à l’écrire proprement pour éviter les effets de bord.
Mettre en place la redirection correctement en PHP
La forme la plus simple consiste à envoyer l’en-tête Location puis à arrêter le script. C’est la base, mais il y a une règle que je ne contourne jamais : tu coupes l’exécution juste après. Sinon, le code suivant peut continuer à produire des effets secondaires, écrire du contenu ou déclencher d’autres traitements alors que le client est déjà parti ailleurs.
Pour une migration permanente, je préfère être explicite sur le code :
Et après un POST, le schéma le plus propre reste souvent celui-ci :
Quelques réflexes me paraissent non négociables :
- placer la redirection avant tout affichage HTML ou espace blanc inutile ;
- utiliser un chemin relatif si la cible reste dans le même site, par exemple
/compte; - employer une URL absolue si la destination change de domaine ;
- choisir le code de statut au lieu de laisser le 302 implicite ;
- terminer immédiatement avec
exitoudie.
Cette mécanique est simple, mais elle ne pardonne pas les entrées mal contrôlées. C’est précisément là que les problèmes de sécurité et de stabilité commencent.
Éviter les pièges de sécurité et les boucles
Le risque classique, c’est la redirection ouverte. L’utilisateur fournit une URL de destination, le serveur la recopie, et un attaquant s’en sert pour envoyer quelqu’un vers un site de phishing. OWASP recommande de ne pas accepter une URL brute comme cible et de préférer un identifiant court, mappé côté serveur vers une destination autorisée.
Je conseille donc un modèle simple : le client envoie une clé, pas une URL complète. Le backend fait la correspondance dans une liste blanche locale. Exemple :
'/tableau-de-bord',
'profil' => '/compte/profil',
'facturation' => '/compte/facturation',
];
$key = $_GET['next'] ?? 'dashboard';
$target = $targets[$key] ?? '/tableau-de-bord';
header('Location: ' . $target, true, 302);
exit;Si une destination externe est vraiment nécessaire, je préfère parser l’URL et comparer strictement le domaine attendu. Pas d’expression régulière approximative, pas de tolérance sur le schéma, pas de raccourci “on verra en production”. En matière de redirection, les petites libertés deviennent vite des failles.
L’autre piège fréquent est la boucle infinie. Elle apparaît quand une règle renvoie vers une URL qui repasse immédiatement dans la même règle, souvent après une migration partielle ou un mauvais test de session. Pour la casser, je vérifie toujours la cible effective avant d’émettre l’en-tête, et je surveille les fichiers inclus qui pourraient envoyer du contenu invisible avant la redirection.
Enfin, n’ignore pas les symptômes classiques de headers already sent. Un espace avant , un echo oublié, ou un fichier inclus qui affiche quelque chose suffit à bloquer la réponse. Dans ce cas, je traite le problème à la source plutôt que de masquer la panne avec du buffering. La technique est utile, mais elle ne remplace pas une réponse propre.
Une fois ces bases sécurisées, la vraie question devient : faut-il vraiment rediriger dans un backend ou une API, et si oui, à quel moment exactement ?
Redirections utiles dans une API ou un backend moderne
Dans une interface web classique, la redirection est naturelle. Dans une API, elle doit être plus réfléchie. Un client machine ne “clique” pas, il enchaîne des requêtes selon un contrat. Si je redirige trop souvent ou au mauvais code, je risque de casser ce contrat, surtout sur des clients HTTP stricts ou sur des intégrations tierces.
Je réserve les redirections API à quelques scénarios précis :
- migration d’un endpoint vers une nouvelle version stable ;
- bascule temporaire pendant une maintenance ou un incident ;
- flux POST-Redirect-GET sur une partie web du backend ;
- retour après authentification vers une page de reprise ;
- déplacement définitif d’une ressource avec conservation du verbe quand c’est nécessaire.
Pour une soumission de formulaire ou un parcours utilisateur, le trio le plus robuste reste souvent POST puis 303 puis page de confirmation. Cela évite les doublons lors du rafraîchissement. Pour une API qui doit conserver la méthode, je privilégie 307 ou 308, car ils gardent le corps de la requête intact. C’est important dès qu’un client envoie des données sensibles ou structurées qu’il ne faut pas transformer en GET par accident.
Dans les architectures plus sérieuses, je me méfie aussi des redirections “pour masquer” un problème de conception. Si un service change trop souvent d’URL, si une API passe son temps à rediriger vers une autre, il est souvent plus propre de corriger le routage au niveau du proxy, du gateway ou de la configuration applicative plutôt que d’imposer un détour au client. La redirection est un outil de transition, pas un substitut permanent à une architecture claire.
Une fois ce cadre posé, il ne reste plus qu’à vérifier les derniers détails avant mise en production.
Les derniers contrôles que je fais avant de déployer
Avant d’envoyer une redirection en production, je passe toujours par une vérification courte mais stricte. Elle me prend peu de temps et m’évite les problèmes les plus coûteux à diagnostiquer après coup :
- la cible est-elle bien celle voulue, et pas une URL saisie par l’utilisateur ?
- le bon code HTTP est-il envoyé explicitement ?
- aucun contenu n’est-il sorti avant les en-têtes ?
- le script se termine-t-il immédiatement après la redirection ?
- la règle ne peut-elle pas créer une boucle sur une route déjà migrée ?
- le comportement est-il correct avec
curl, un navigateur et un client API ? - la migration doit-elle être mise en cache ou rester temporaire ?
Je vérifie aussi le contexte de déploiement : proxy, CDN, cache applicatif, HSTS, pages de maintenance et éventuelles règles du serveur web peuvent modifier le résultat perçu par le client. Sur un site à fort trafic, la différence entre un 302 laissé par défaut et un 301 ou 308 assumé peut changer la façon dont le trafic, les robots et les intégrations réagissent pendant des semaines. Si je dois retenir une seule règle, c’est celle-ci : une redirection n’est pas juste une URL de remplacement, c’est une décision de protocole.
Quand la logique est claire, la mise en œuvre en PHP reste très légère. Ce qui fait la différence, ce ne sont pas des lignes de code supplémentaires, mais le choix du bon statut, la maîtrise des entrées et le respect du contrat HTTP jusqu’au bout.