Keine Ausgabe vor dem Senden von Kopfzeilen!
Funktionen zum Senden/Ändern von HTTP-Headern müssen aufgerufen werden bevor irgendeine Ausgabe gemacht wird . <a href="https://stackoverflow.com/a/8028979/345031"><strong>summary </strong></a> Andernfalls schlägt der Aufruf fehl:
Warnung: Cannot modify header information - headers already sent (Ausgabe begann bei Skript:Zeile )
Einige Funktionen, die den HTTP-Header verändern, sind:
Die Ausgabe kann sein:
-
Unbeabsichtigt:
- Whitespace vor
<?php
oder nach ?>
- El UTF-8 Byte Order Mark speziell
- Frühere Fehlermeldungen oder Hinweise
-
Absichtlich:
print
, echo
und andere Funktionen, die eine Ausgabe erzeugen
- Rohe
<html>
Abschnitte vorher <?php
Code.
Wie kommt es dazu?
Um zu verstehen, warum Kopfzeilen vor der Ausgabe gesendet werden müssen, ist es notwendig einen Blick auf eine typische HTTP Antwort. PHP-Skripte erzeugen hauptsächlich HTML-Inhalte, übergeben aber auch eine eine Reihe von HTTP/CGI-Headern an den Webserver:
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="http://stackoverflow.com/"> <img src=internal-icon-delayed> </a>
Die Seite/Ausgabe ist immer folgt die Kopfzeilen. PHP muss die Header zuerst an den Webserver weitergeben. Das kann es nur einmal tun. Nach dem doppelten Zeilenumbruch kann es sie nicht mehr ändern.
Wenn PHP die erste Ausgabe erhält ( print
, echo
, <html>
) wird es Spülen alle gesammelten Kopfzeilen. Danach kann er alle gewünschten Ausgaben die er will. Aber das Senden weiterer HTTP-Header ist dann unmöglich.
Wie können Sie herausfinden, wo die vorzeitige Ausgabe erfolgt ist?
El header()
Warnung enthält alle relevanten Informationen, um die Ursache des Problems zu finden:
Warnung: Cannot modify header information - headers already sent by (die Ausgabe begann bei /www/usr2345/htdocs/ auth.php:52 ) in /www/usr2345/htdocs/index.php in Zeile 100
Hier bezieht sich "Zeile 100" auf das Skript, in dem die header()
Aufruf gescheitert.
Die " Die Ausgabe begann bei "Der Hinweis in der Klammer ist von größerer Bedeutung. Er bezeichnet die Quelle der vorherigen Ausgabe. In diesem Beispiel ist es auth.php
y Zeile 52
. Das ist der Punkt, an dem man nach vorzeitigem Output suchen muss.
Typische Ursachen:
-
Drucken, Echo
Beabsichtigte Ausgabe von print
y echo
Anweisungen wird die Möglichkeit, HTTP-Header zu senden, beendet. Um dies zu vermeiden, muss der Anwendungsablauf umstrukturiert werden. verwenden funciones und Schemata. Sicherstellen header()
Anrufe erfolgen vor Nachrichten ausgeschrieben werden.
Zu den Funktionen, die eine Ausgabe erzeugen, gehören
print
, echo
, printf
, vprintf
trigger_error
, ob_flush
, ob_end_flush
, var_dump
, print_r
readfile
, passthru
, flush
, imagepng
, imagejpeg
unter anderem und benutzerdefinierte Funktionen.
-
Rohe HTML-Bereiche
Unparsed HTML-Abschnitte in einer .php
Datei werden ebenfalls direkt ausgegeben. Skriptbedingungen, die eine header()
Anruf muss vermerkt werden vor cualquier roh <html>
Blöcke.
<!DOCTYPE html>
<?php
// Too late for headers already.
Verwenden Sie ein Schablonenschema, um die Verarbeitung von der Ausgabelogik zu trennen.
- Platzieren Sie den Code für die Formularverarbeitung in Skripten.
- Verwenden Sie temporäre String-Variablen, um Nachrichten zu verschieben.
- Die eigentliche Ausgabelogik und die eingemischte HTML-Ausgabe sollten zuletzt folgen.
-
Whitespace vor <?php
für "script.php Zeile 1 " Warnungen
Wenn sich die Warnung auf die Inline-Ausgabe bezieht 1
dann ist es meistens führend Leerzeichen , Text oder HTML vor der Öffnung <?php
Token.
<?php
# There's a SINGLE space/newline before <? - Which already seals it.
Ähnlich kann es bei angehängten Skripten oder Skriptabschnitten vorkommen:
?>
<?php
PHP frisst tatsächlich eine einzeln Zeilenumbruch nach Close-Tags. Aber es wird nicht mehrere Zeilenumbrüche oder Tabulatoren oder Leerzeichen, die in solche Lücken verschoben werden, nicht kompensieren.
-
UTF-8 BOM
Zeilenumbrüche und Leerzeichen allein können ein Problem darstellen. Aber es gibt auch "unsichtbare" Zeichenfolgen, die dies verursachen können. Am bekanntesten ist die UTF-8 BOM (Byte-Order-Marke) die von den meisten Texteditoren nicht angezeigt wird. Es handelt sich um die Bytefolge EF BB BF
die bei UTF-8-kodierten Dokumenten optional und überflüssig ist. PHP muss sie jedoch als Rohausgabe behandeln. Sie kann als die folgenden Zeichen angezeigt werden in der Ausgabe (wenn der Client das Dokument als Latin-1 interpretiert) oder ähnlichen "Müll".
Vor allem grafische Editoren und Java-basierte IDEs kennen es nicht Präsenz. Sie zeigen es nicht an (was durch den Unicode-Standard vorgeschrieben ist). Die meisten Programmier- und Konsoleneditoren hingegen schon:
![joes editor showing UTF-8 BOM placeholder, and MC editor a dot]()
Dort ist es einfach, das Problem frühzeitig zu erkennen. Andere Editoren erkennen möglicherweise das Vorhandensein in einem Datei-/Einstellungsmenü (Notepad++ unter Windows kann es erkennen und das Problem zu beheben ), Eine weitere Möglichkeit, das Vorhandensein von Stücklisten zu prüfen, ist der Rückgriff auf eine hexeditor . Auf *nix-Systemen hexdump
ist normalerweise verfügbar, wenn nicht sogar eine grafische Variante, die die Prüfung dieser und anderer Fragen vereinfacht:
![beav hexeditor showing utf-8 bom]()
Eine einfache Lösung besteht darin, den Texteditor so einzustellen, dass Dateien als "UTF-8 (no BOM)" gespeichert werden. oder einer ähnlichen Nomenklatur zu speichern. Andernfalls erstellen Neulinge oft neue Dateien und fügen den vorherigen Code einfach per Copy & Paste wieder ein.
Berichtigung Dienstprogramme ![]()
Es gibt auch automatisierte Tools, um Textdateien zu untersuchen und neu zu schreiben ( sed
/ awk
ou recode
). Speziell für PHP gibt es die phptags
Tag ordentlicher . Es schreibt Close- und Open-Tags in Lang- und Kurzformen um, behebt aber auch leicht behebt führende und nachgestellte Leerzeichen, Unicode- und UTF-x-BOM-Probleme:
phptags --whitespace *.php
Es ist sicher, auf ein ganzes Include- oder Projektverzeichnis anzuwenden.
-
Whitespace nach ?>
Wenn die Fehlerquelle als hinter dem Schließen ?>
dann ist dies der Ort, an dem Leerraum oder der Rohtext herausgeschrieben wurde. Die PHP-Endmarkierung beendet die Skriptausführung an dieser Stelle nicht. Jeder Text/jedes Leerzeichen danach wird als Seiteninhalt ausgegeben noch.
Es wird allgemein empfohlen, insbesondere für Neueinsteiger, dass die ?>
PHP close-Tags sollten weggelassen werden. Diese unterlässt ein kleiner Teil dieser Fälle. (Ziemlich häufig include()d
Skripte sind der Übeltäter).
-
Die Fehlerquelle wird als "Unbekannt in Zeile 0" angegeben.
Normalerweise ist es eine PHP-Erweiterung oder eine php.ini-Einstellung, wenn keine Fehlerquelle konkretisiert ist.
- Gelegentlich ist es die
gzip
Stream-Codierungseinstellung oder die ob_gzhandler
.
- Es könnte sich aber auch um jede doppelt geladene
extension=
Modul das eine implizite PHP-Start-/Warnmeldung erzeugt.
-
Vorangegangene Fehlermeldungen
Wenn eine andere PHP-Anweisung oder ein Ausdruck eine Warnmeldung oder Hinweis ausgibt, zählt dies ebenfalls als vorzeitige Ausgabe.
In diesem Fall müssen Sie den Fehler beseitigen, die Ausführung der Anweisung verzögern oder die Meldung unterdrücken, z. B. mit isset()
ou @()
- wenn beides die spätere Fehlersuche nicht behindert.
Keine Fehlermeldung
Wenn Sie eine error_reporting
ou display_errors
deaktiviert pro php.ini
, dann wird keine Warnung angezeigt. Aber das Ignorieren von Fehlern führt nicht dazu, dass das Problem verschwindet. verschwinden. Kopfzeilen können nach einer vorzeitigen Ausgabe immer noch nicht gesendet werden.
Wenn also header("Location: ...")
Umleitungen stillschweigend scheitern, ist es sehr ratsam, auf Warnungen zu achten. Sie können mit zwei einfachen Befehlen wieder aktiviert werden oberhalb des Aufrufskripts:
error_reporting(E_ALL);
ini_set("display_errors", 1);
Oder set_error_handler("var_dump");
wenn alles andere versagt.
Apropos Redirect-Header, Sie sollten oft eine Redewendung wie für endgültige Codepfade verwenden:
exit(header("Location: /finished.html"));
Vorzugsweise sogar eine Hilfsfunktion, die eine Benutzermeldung ausgibt im Falle von header()
Ausfälle.
Ausgabepufferung als Abhilfe
PHPs Ausgangspufferung ist eine Abhilfemaßnahme, um dieses Problem zu beheben. Sie funktioniert oft zuverlässig, sollte aber nicht die richtige Strukturierung der Anwendung und die Trennung von Ausgabe und Steuerung logik. Ihr eigentlicher Zweck ist die Minimierung von Chunked-Transfers zum Webserver.
-
El output_buffering=
Einstellung kann dennoch helfen. Konfigurieren Sie sie in der php.ini oder über .htaccess oder sogar .user.ini auf modernen FPM/FastCGI-Konfigurationen.
Wenn Sie diese Option aktivieren, kann PHP die Ausgabe puffern, anstatt sie sofort an den Webserver zu übergeben. PHP kann somit HTTP-Header aggregieren.
-
Sie kann ebenfalls mit einem Aufruf zur ob_start();
auf dem Aufrufskript. Dies ist jedoch aus mehreren Gründen weniger zuverlässig:
-
Auch wenn <?php ob_start(); ?>
beginnt das erste Skript, Leerzeichen oder ein BOM könnte vorher gemischt werden, und damit unwirksam machen .
-
Es kann Leerzeichen für die HTML-Ausgabe verbergen. Sobald jedoch die Anwendungslogik versucht, binäre Inhalte zu senden (z. B. ein generiertes Bild) wird die gepufferte fremde Ausgabe zum Problem. (Erforderlich ob_clean()
als weitere Abhilfe).
-
Der Puffer ist in seiner Größe begrenzt und kann leicht überlaufen, wenn er auf die Standardeinstellungen zurückgesetzt wird. Und auch das ist kein seltenes Vorkommnis, schwer auffindbar wenn es passiert.
Beide Ansätze können daher unzuverlässig werden - vor allem beim Wechsel zwischen Entwicklungs-Setups und/oder Produktionsservern. Aus diesem Grund wird die Ausgabepufferung weithin nur als Krücke / reine Notlösung angesehen.
Siehe auch die grundlegendes Anwendungsbeispiel im Handbuch und für weitere Vor- und Nachteile:
Aber auf dem anderen Server hat es funktioniert!?
Wenn Sie die Kopfzeilen-Warnung vorher nicht erhalten haben, dann ist die Ausgangspufferung php.ini-Einstellung hat sich geändert. Er ist wahrscheinlich auf dem aktuellen/neuen Server nicht konfiguriert.
Prüfen mit headers_sent()
Sie können jederzeit die headers_sent()
zu prüfen, ob es immer noch möglich ist... Kopfzeilen zu senden. Das ist nützlich, um bedingte Info zu drucken oder andere Fallback-Logik anzuwenden.
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
Nützliche Behelfslösungen sind:
-
HTML <meta>
Tag
Wenn Ihre Anwendung strukturell schwer zu reparieren ist, dann ist eine einfache (aber eine einfache (aber etwas unprofessionelle) Möglichkeit, Weiterleitungen zuzulassen, die Einfügung eines HTML <meta>
Tag. Eine Weiterleitung kann mit erreicht werden:
<meta http-equiv="Location" content="http://example.com/">
Oder mit einer kurzen Verzögerung:
<meta http-equiv="Refresh" content="2; url=../target.html">
Dies führt zu ungültigem HTML, wenn es hinter dem <head>
Abschnitt. Die meisten Browser akzeptieren sie noch.
-
JavaScript-Weiterleitung
Als Alternative ein JavaScript-Weiterleitung kann für Seitenumleitungen verwendet werden:
<script> location.replace("target.html"); </script>
Dies ist zwar oft HTML-kompatibler als die <meta>
Abhilfe, ist er auf JavaScript-fähige Clients angewiesen.
Beide Ansätze sind jedoch akzeptable Ausweichlösungen, wenn echte HTTP-Header() Aufrufe fehlschlagen. Idealerweise kombinieren Sie dies immer mit einer benutzerfreundlichen Meldung und anklickbaren Link als letzten Ausweg. (Das ist zum Beispiel das, was die http_redirect() PECL-Erweiterung).
Warum setcookie()
y session_start()
sind ebenfalls betroffen
Beide setcookie()
y session_start()
Sie müssen eine Set-Cookie:
HTTP-Header. Es gelten daher die gleichen Bedingungen, und es werden ähnliche Fehlermeldungen erzeugt für vorzeitige Ausgabesituationen erzeugt.
(Natürlich sind sie auch von deaktivierten Cookies im Browser betroffen. oder sogar Proxy-Probleme. Die Sitzungsfunktionalität hängt natürlich auch von freiem Speicherplatz und anderen php.ini-Einstellungen usw. ab)
Weitere Links