vendredi 25 septembre 2026

À propos

Contact

Extensions

« Cannot modify header information – headers already sent » : trouver la cause

Le message le plus mal compris de PHP dans une extension WordPress : il ne pointe presque jamais vers l'endroit réel du problème. Voici la méthode pour remonter à la source.

Par Clément Hadrot • 12 février 2021 • 4 min de lecture • Aucun commentaire
« Cannot modify header information – headers already sent » : trouver la cause

Symptôme. Une extension personnalisée développée pour un client du secteur associatif provoquait, de façon intermittente, le message Warning: Cannot modify header information - headers already sent by (output started at ...) au moment de sauvegarder un formulaire d’adhésion. La redirection censée suivre la sauvegarde ne se produisait jamais, laissant l’utilisateur face à un écran d’erreur PHP en haut de page.

Comprendre ce que dit réellement le message

La première confusion à dissiper : le message d’erreur indique où PHP a tenté d’envoyer un en-tête HTTP en échec (généralement un appel à wp_redirect(), wp_safe_redirect() ou setcookie()), pas où la sortie parasite a commencé. La mention « output started at » donne heureusement cette seconde information, mais elle pointe souvent vers un fichier totalement éloigné du code qu’on soupçonne en premier.

Warning: Cannot modify header information - headers already sent
by (output started at /wp-content/plugins/kaolin-adhesions/kaolin-adhesions.php:1)
in /wp-includes/pluggable.php on line 1408

Ici, le numéro de ligne 1 du fichier principal de l’extension est le vrai indice : une sortie s’est produite dès la première ligne du fichier, bien avant que le code métier n’ait eu la moindre chance de s’exécuter.

Diagnostic : traquer la sortie parasite

Dans l’immense majorité des cas que j’ai rencontrés, la cause se limite à quatre possibilités, classées par fréquence décroissante.

L'essentiel à retenir : Le message indique où PHP a tenté d'envoyer un en-tête, pas où la sortie a commencé ; Un BOM invisible ou un espace avant <?php suffit à déclencher l'erreur ; output_buffering peut masquer temporairement le symptôme sans corriger la cause
  • Un espace, une tabulation ou un retour à la ligne avant la balise ouvrante <?php du fichier concerné
  • Une balise fermante ?> en fin de fichier, suivie d’un retour à la ligne invisible dans l’éditeur
  • Un caractère BOM (byte order mark) inséré silencieusement par certains éditeurs de texte lors de l’enregistrement en UTF-8
  • Un appel de débogage oublié (echo, print_r, var_dump) exécuté avant la tentative de redirection

Pour ce projet précis, la cause était la troisième : le fichier principal avait été réenregistré par un éditeur de texte configuré en « UTF-8 avec BOM » après une intervention rapide d’un collègue, ajoutant trois octets invisibles en tout début de fichier. Ces trois octets suffisent à constituer une sortie, même si aucun caractère visible n’apparaît à l’écran.

Correctif : localiser et supprimer la sortie

La commande grep en ligne de commande permet de repérer rapidement les balises fermantes suspectes dans l’ensemble des fichiers d’une extension :

grep -rn '?>$' wp-content/plugins/kaolin-adhesions/

Pour un BOM, un éditeur de texte capable d’afficher les caractères invisibles (ou une commande comme file sous Linux) permet de le confirmer :

file wp-content/plugins/kaolin-adhesions/kaolin-adhesions.php
# renvoie : ... UTF-8 Unicode (with BOM) text

Le correctif consiste à réenregistrer le fichier en UTF-8 sans BOM, une option disponible dans la quasi-totalité des éditeurs modernes, puis à supprimer toute balise fermante ?> en fin de fichier PHP — elle n’est jamais requise par l’interpréteur et sa seule utilité est de créer ce genre de bug.

// Avant, en fin de fichier :
function kaolin_traiter_adhesion() { /* ... */ }
?>


// Après :
function kaolin_traiter_adhesion() { /* ... */ }

Prévention : éviter que le problème ne revienne

Trois habitudes ont éliminé ce type d’incident pour de bon sur les projets suivants de cette agence.

  • Bannir systématiquement la balise fermante ?> en fin de fichier PHP, dans tous les fichiers de l’extension
  • Configurer l’éditeur de l’équipe en UTF-8 sans BOM par défaut pour tous les fichiers PHP
  • Ajouter une vérification automatique dans le processus d’intégration continue, via un script simple qui détecte les BOM sur l’ensemble du dépôt avant chaque déploiement

Un dépannage utile en urgence, mais à ne jamais considérer comme un correctif définitif : activer ob_start() en tout début de fichier avale la sortie parasite et fait disparaître le symptôme, sans supprimer sa cause. Le problème resurgit inévitablement, souvent dans un contexte où ob_start() n’a pas été pensé.

En résumé

« Headers already sent » n’est jamais une erreur aléatoire : c’est toujours une sortie physique, même invisible, qui s’est produite avant l’appel qui échoue. La méthode reste constante d’un projet à l’autre : lire attentivement la mention « output started at », vérifier balise fermante, espaces parasites et BOM dans le fichier indiqué, puis remonter au code de débogage oublié si les trois premières pistes ne donnent rien.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi