Question Comment réparer l'erreur "Headers already sent" en PHP


Lors de l'exécution de mon script, je reçois plusieurs erreurs comme celle-ci:

Attention: Impossible de modifier les informations d'en-tête - en-têtes déjà envoyés par (la sortie a commencé à /some/file.php:12) dans /some/file.php sur ligne 23

Les lignes mentionnées dans les messages d'erreur contiennent header() et setcookie() appels.

Quelle pourrait en être la raison? Et comment le réparer?


836
2017-11-06 17:45


origine


Réponses:


Pas de sortie avant d'envoyer les en-têtes!

Les fonctions qui envoient / modifient les en-têtes HTTP doivent être appelées avant toute sortie. résumé ⇊ Sinon, l'appel échoue:

Attention: Impossible de modifier les informations d'en-tête - en-têtes déjà envoyés (sortie démarrée à script: ligne)

Certaines fonctions modifiant l'en-tête HTTP sont:

La sortie peut être:

  • Intentionnel:

    • print, echo et d'autres fonctions produisant des résultats
    • Brut <html> sections précédentes <?php code.

Pourquoi cela arrive-t-il?

Pour comprendre pourquoi les en-têtes doivent être envoyés avant la sortie, il est nécessaire regarder un typique HTTP réponse. Les scripts PHP génèrent principalement du contenu HTML, mais ensemble d'en-têtes HTTP / CGI sur le serveur web:

HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>

La page / sortie toujours suit les en-têtes. PHP doit passer le les en-têtes au serveur Web en premier. Il ne peut le faire qu'une seule fois. Après le double saut de ligne, il ne peut jamais les modifier.

Quand PHP reçoit la première sortie (print, echo, <html>) ce sera affleurer tous les en-têtes collectés. Ensuite, il peut envoyer toute la sortie ça veut. Mais envoyer d'autres en-têtes HTTP est impossible alors.

Comment pouvez-vous savoir où la sortie prématurée s'est produite?

le header() avertissement contient toutes les informations pertinentes à localiser la cause du problème:

Attention: Impossible de modifier les informations d'en-tête - en-têtes déjà envoyés par    (la sortie a commencé à / www / usr2345 / htdocs /auth.php: 52) dans   /www/usr2345/htdocs/index.php à la ligne 100

Ici "ligne 100" se réfère au script où le header()  invocation échoué.

Le "sortie a commencé à"note dans la parenthèse est plus significative. Il dénomme la source de sortie précédente. Dans cet exemple c'est auth.php et ligne 52. C'est là que vous deviez rechercher une sortie prématurée.

Causes typiques:

  1. Impression, écho

    Sortie intentionnelle de print et echo les déclarations se termineront la possibilité d'envoyer des en-têtes HTTP. Le flux d'application doit être restructuré pour éviter cela. Utilisation les fonctions et des schémas de modèles. Assurer header() les appels se produisent avant messages sont écrits.

    Les fonctions qui produisent la sortie incluent

    • print, echo, printf, vprintf
    • trigger_error, ob_flush, ob_end_flush, var_dump, print_r
    • readfile, passthru, flush, imagepng, imagejpeg


     entre autres et des fonctions définies par l'utilisateur.

  2. Zones HTML brutes

    Sections HTML non analysées dans un .php le fichier sont également en sortie directe. Conditions de script qui déclencheront un header() appel doit être noté avant tout brut <html> des blocs.

    <!DOCTYPE html>
    <?php
        // Too late for headers already.
    

    Utilisez un schéma de modèle pour séparer le traitement de la logique de sortie.

    • Placez le code de traitement de formulaire au sommet des scripts.
    • Utilisez des variables de chaîne temporaires pour différer les messages.
    • La logique de sortie réelle et la sortie HTML mélangée devraient suivre en dernier.

  3. Espace avant <?php pour "script.php ligne 1" avertissements

    Si l'avertissement se réfère à la sortie en ligne 1alors c'est surtout de premier plan espace, texte ou HTML avant l'ouverture <?php jeton.

     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.
    

    De même, cela peut se produire pour les scripts ou les sections de script ajoutés:

    ?>
    
    <?php
    

    PHP mange réellement un unique linebreak après des balises proches. Mais ce ne sera pas Compenser plusieurs nouvelles lignes ou des onglets ou des espaces décalés dans de telles lacunes.

  4. BOM UTF-8

    Les sauts de ligne et les espaces seuls peuvent être un problème. Mais il y a aussi "invisible" séquences de caractères qui peuvent provoquer cela. Le plus célèbre est le BOM UTF-8 (Byte-Order-Mark) qui n'est pas affiché par la plupart des éditeurs de texte. C'est la séquence d'octets EF BB BF, lequel est optionnel et redondant pour les documents codés en UTF-8. PHP doit cependant traiter comme sortie brute. Il peut apparaître comme les caractères  dans la sortie (si le client interprète le document comme Latin-1) ou similaire "garbage".

    En particulier les éditeurs graphiques et les IDE basés sur Java sont inconscients de son présence. Ils ne le visualisent pas (obligé par la norme Unicode). Cependant, la plupart des éditeurs de programmeurs et de consoles font ce qui suit:

    joes editor showing UTF-8 BOM placeholder, and MC editor a dot

    Là, il est facile de reconnaître le problème dès le début. D'autres éditeurs peuvent identifier sa présence dans un menu fichier / paramètres (Notepad ++ sur Windows peut identifier et remédier au problème), Une autre option pour inspecter la présence de la nomenclature consiste à recourir à un hexeditor. Sur les systèmes * nix hexdump est habituellement disponible, sinon une variante graphique qui simplifie l'audit de ces questions et d'autres:

    beav hexeditor showing utf-8 bom

    Une solution facile consiste à définir l'éditeur de texte pour enregistrer les fichiers en tant que "UTF-8 (no BOM)" ou similaire semblable nomenclature. Souvent, les nouveaux arrivants recourent à la création de fichiers et juste copier et coller le code précédent.

    Utilitaires de correction

    Il existe également des outils automatisés pour examiner et réécrire les fichiers texte (sed/awk ou recode). Pour PHP en particulier, il y a le phptags tag tidier. Il réécrit les balises proches et ouvertes en formes longues et courtes, mais aussi facilement corrige les problèmes d'espace blanc, d'Unicode et de BOM UTF-x de début et de fin:

    phptags  --whitespace  *.php
    

    Il est sain d'utiliser tout un répertoire d'inclusion ou de projet.

  5. Espace après ?>

    Si la source d'erreur est mentionnée derrière le fermeture ?> alors c'est où un espace ou un texte brut a été écrit. Le marqueur de fin PHP ne termine pas l'exécution du script à ce moment-là point. Tout caractère de texte / espace après il sera écrit en tant que contenu de la page encore.

    Il est généralement conseillé, en particulier aux nouveaux arrivants, ?> PHP les balises de fermeture doivent être omises. Ce éviter une petite partie de ces cas. (Assez communément include()d les scripts sont les coupables.)

  6. La source d'erreur mentionnée est "Unknown on line 0"

    C'est généralement une extension PHP ou un paramètre php.ini si aucune source d'erreur est concrétisé.

    • C'est parfois le gzip paramètre d'encodage de flux ou la ob_gzhandler.
    • Mais il pourrait aussi être doublement chargé extension= module générer un message de démarrage / d'avertissement PHP implicite.

  7. Messages d'erreur précédents

    Si une autre instruction ou expression PHP provoque un message d'avertissement ou l'avis étant imprimé, cela compte aussi comme sortie prématurée.

    Dans ce cas, vous devez éviter l'erreur, retarder l'exécution de l'instruction, ou supprimer le message avec par ex. isset() ou @() - quand l'un ou l'autre n'empêche pas le débogage plus tard.

Aucun message d'erreur

Si tu as error_reporting ou display_errors désactivé par php.ini, alors aucun avertissement n'apparaîtra. Mais ignorer les erreurs ne fera pas disparaître le problème un moyen. Les en-têtes ne peuvent toujours pas être envoyés après une sortie prématurée.

Donc quand header("Location: ...") redirige silencieusement échouer c'est très conseillé de rechercher des avertissements. Réactivez-les avec deux commandes simples au sommet du script d'invocation:

error_reporting(E_ALL);
ini_set("display_errors", 1);

Ou set_error_handler("var_dump"); si tout le reste échoue.

En parlant d'en-têtes de redirection, vous devriez souvent utiliser un idiome comme ceci pour les chemins de code finaux:

exit(header("Location: /finished.html"));

De préférence, même une fonction d'utilité, qui imprime un message d'utilisateur en cas de header() les échecs.

Tampon de sortie comme solution de contournement

Les PHPs sortie tampon est une solution de contournement pour résoudre ce problème. Il fonctionne souvent de manière fiable, mais ne devrait pas se substituer à la bonne structuration de l'application et séparer la sortie du contrôle logique. Son but réel est de minimiser les transferts en morceaux sur le serveur Web.

  1. le output_buffering= réglage peut néanmoins aider. Configurez-le dans le php.ini ou via .htaccess ou même .user.ini sur configurations FPM / FastCGI modernes.
    L'activer permettra à PHP de mettre en tampon la sortie au lieu de la transmettre au serveur web immédiatement. PHP peut donc agréger les en-têtes HTTP.

  2. Il peut également être engagé avec un appel à ob_start(); au sommet du script d'invocation. Lequel est cependant moins fiable pour plusieurs raisons:

    • Même si <?php ob_start(); ?> commence le premier script, un espace ou un La nomenclature peut être mélangée avant, le rendant inefficace.

    • Il peut masquer les espaces pour la sortie HTML. Mais dès que l'application la logique tente d'envoyer du contenu binaire (une image générée par exemple), la sortie étrangère tamponnée devient un problème. (Nécessitant ob_clean() comme solution de contournement plus loin.)

    • La taille du tampon est limitée et peut facilement être dépassée en cas de défaut. Et ce n'est pas une occurrence rare non plus, difficile de traquer quand ça arrive.

Les deux approches peuvent donc devenir peu fiables - en particulier lors de la commutation entre configurations de développement et / ou serveurs de production. C'est pourquoi la mise en tampon de sortie est largement considéré comme une béquille / strictement une solution de contournement.

Voir aussi exemple d'utilisation basique dans le manuel, et pour plus de avantages et inconvénients:

Mais cela a fonctionné sur l'autre serveur !?

Si vous n'avez pas reçu les avertissements d'en-tête avant, le sortie tampon  Paramètre php.ini  a changé. Il est probablement non configuré sur le serveur actuel / nouveau.

Vérification avec headers_sent()

Vous pouvez toujours utiliser headers_sent() pour sonder si il est toujours possible de ... envoyer des en-têtes. Ce qui est utile pour imprimer sous conditions une info ou appliquer une autre logique de secours.

if (headers_sent()) {
    die("Redirect failed. Please click on this link: <a href=...>");
}
else{
    exit(header("Location: /user.php"));
}

Solutions de rechange utiles de secours sont:

  • HTML <meta> marque

    Si votre application est structurellement difficile à résoudre, alors un facile (mais façon un peu professionnelle) pour autoriser les redirections injecte un code HTML <meta> marque. Une redirection peut être réalisée avec:

     <meta http-equiv="Location" content="http://example.com/">
    

    Ou avec un court délai:

     <meta http-equiv="Refresh" content="2; url=../target.html">
    

    Cela conduit à un code HTML non valide lorsqu'il est utilisé après le <head> section. La plupart des navigateurs l'acceptent toujours.

  • Redirection JavaScript

    Comme alternative a Redirection JavaScript peut être utilisé pour les redirections de pages:

     <script> location.replace("target.html"); </script>
    

    Bien que ce soit souvent plus conforme HTML que le <meta> solution de contournement, il engage une dépendance sur les clients capables de JavaScript.

Les deux approches font cependant des solutions de repli acceptables lorsqu'une véritable entête HTTP () les appels échouent. Idéalement, vous combinerez toujours cela avec un message convivial et lien cliquable en dernier recours. (Qui est par exemple ce que le http_redirect () PECL extension fait.)

Pourquoi setcookie() et session_start() sont également affectés

Tous les deux setcookie() et session_start() besoin d'envoyer un Set-Cookie: En-tête HTTP. Les mêmes conditions s'appliquent donc et des messages d'erreur similaires seront générés pour les situations de sortie prématurée.

(Bien sûr, ils sont en outre affectés par les cookies désactivés dans le navigateur, ou même des problèmes de proxy. La fonctionnalité de session dépend évidemment aussi gratuitement espace disque et autres paramètres php.ini, etc.)

Liens supplémentaires


2640
2017-11-06 17:44



Ce message d'erreur est déclenché lorsque n'importe quoi est envoyé avant d'envoyer les en-têtes HTTP (avec setcookie ou header). Les raisons communes pour sortir quelque chose avant les en-têtes HTTP sont:

  • Espace accidentel, souvent au début ou à la fin des fichiers, comme ceci:

     <?php
    // Note the space before "<?php"
    ?>
    

Pour éviter cela, laissez simplement la fermeture ?> - Ce n'est pas nécessaire de toute façon.

  • Marques d'ordre d'octet au début d'un fichier php. Examinez vos fichiers php avec un éditeur hexadécimal pour savoir si c'est le cas. Ils devraient commencer par les octets 3F 3C. Vous pouvez supprimer la nomenclature en toute sécurité EF BB BF depuis le début des fichiers.
  • Sortie explicite, telle que les appels à echo, printf, readfile, passthru, code avant <? etc.
  • Un avertissement produit par php, si le display_errors La propriété php.ini est définie. Au lieu de s'écraser sur une erreur de programmeur, PHP répare silencieusement l'erreur et émet un avertissement. Alors que vous pouvez modifier le display_errors ou error_reporting configurations, vous devriez plutôt résoudre le problème.
    Les raisons communes sont les accès à des éléments non définis d'un tableau (tels que $_POST['input'] sans utiliser empty ou isset pour tester si l'entrée est définie), ou en utilisant une constante indéfinie au lieu d'une chaîne littérale (comme dans $_POST[input], notez les citations manquantes).

Allumer sortie tampon devrait faire disparaître le problème; tous sortie après l'appel à ob_start est tamponné en mémoire jusqu'à ce que vous libérez le tampon, par ex. avec ob_end_flush.

Cependant, alors que la mise en tampon de sortie évite les problèmes, vous devez vraiment déterminer pourquoi votre application génère un corps HTTP avant l'en-tête HTTP. Ce serait comme prendre un appel téléphonique et discuter de votre journée et la météo avant de dire à l'appelant qu'il a le mauvais numéro.


178
2017-08-01 06:43



J'ai eu cette erreur plusieurs fois avant. Et je suis sûr que tout programmeur PHP au moins une fois eu cette erreur. Pour résoudre cette erreur, vous pouvez résoudre la solution d'utilisation selon votre niveau de problème:

Solution possible 1:

Vous avez peut-être laissé des espaces vides avant ou après (à la fin du fichier après?>) c'est à dire.

THERE SHOULD BE NO BLANK SPACES HERE
<?php  

   echo "your code here";

?>
DO CHECK FOR BLANK SPACES HERE AS WELL; THIS LINE (blank line) SHOULD NOT EXIST.

La plupart du temps cela devrait résoudre votre problème. Vérifiez tous les fichiers associés au fichier require.

Remarque:  Parfois EDITOR (IDE) comme gedit (un éditeur linux par défaut) ajoute une ligne vide sur save save file. Cela ne devrait pas arriver. Si vous utilisez Linux. vous pouvez utiliser l'éditeur VI pour supprimer l'espace / les lignes après?> à la fin de la page.

Si ce n'est pas votre cas, alors vous pouvez utiliser ob_start pour la mise en mémoire tampon de sortie comme ci-dessous:

Solution possible 2:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

101
2018-03-24 12:54



Au lieu de la ligne ci-dessous

//header("Location:".ADMIN_URL."/index.php");

écrire

echo("<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>");

ou

?><script><?php echo("location.href = '".ADMIN_URL."/index.php?msg=$msg';");?></script><?php

Cela va définitivement résoudre votre problème. J'ai fait face au même problème mais j'ai résolu en écrivant l'emplacement de l'en-tête de la manière ci-dessus.


73
2017-11-06 17:45



Tu fais

printf ("Hi %s,</br />", $name);

avant de configurer les cookies, ce qui n'est pas autorisé. Vous ne pouvez pas envoyer de sortie avant les en-têtes, pas même une ligne vide.


38
2017-11-06 17:45



C'est à cause de cette ligne:

printf ("Hi %s,</br />", $name);

Tu ne devrais pas impression / écho quelque chose avant d'envoyer les en-têtes.


29
2018-05-16 20:37



Une astuce simple: Un espace simple (ou un caractère spécial invisible) dans votre script, juste avant le premier <?php tag, peut causer cela! Surtout quand vous travaillez dans une équipe et que quelqu'un utilise un IDE "faible" ou a malmené les fichiers avec des éditeurs de texte étranges.

J'ai vu ces choses;)


25
2017-11-08 01:29