Keine Ausgabe vor dem Senden von Headern!
Funktionen, die HTTP-Header senden / ändern, müssen aufgerufen werden, bevor eine Ausgabe erfolgt .
summary ⇊
Andernfalls schlägt der Anruf fehl:
Warnung: Header-Informationen können nicht geändert werden - Header wurden bereits gesendet (Ausgabe gestartet am Skript: Zeile )
Einige Funktionen, die den HTTP-Header ändern, sind:
Die Ausgabe kann sein:
Absichtlich:
print
, echo
Und andere Funktionen zum Erzeugen von Ausgang
- Roher
<html>
Abschnitt vorheriger <?php
Code.
Warum passiert das?
Um zu verstehen, warum Header vor der Ausgabe gesendet werden müssen, muss eine typische HTTP-
Antwort betrachtet werden. PHP-Skripte generieren hauptsächlich HTML-Inhalte, übergeben aber auch 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="/"> <img src=internal-icon-delayed> </a>
Die Seite / Ausgabe folgt immer den Überschriften. PHP muss zuerst die Header an den Webserver übergeben. Das kann es nur einmal. Nach dem doppelten Zeilenumbruch können sie nie mehr geändert werden.
Wenn PHP den ersten Ausgang empfängt ( print
, echo
, <html>
) wird es
bündig alle gesammelten Header. Danach kann es alle gewünschten Ausgaben senden. Das Senden weiterer HTTP-Header ist dann jedoch nicht möglich.
Wie können Sie herausfinden, wo die vorzeitige Ausgabe stattgefunden hat?
Die header()
Warnung enthält alle relevanten Informationen zum Auffinden der Problemursache:
Warnung: Header-Informationen können nicht geändert werden - Header, die bereits von
(Ausgabe gestartet unter / www / usr2345 / htdocs / auth.php: 52 ) in /www/usr2345/htdocs/index.php in Zeile 100 gesendet wurden
Hier bezieht sich "Zeile 100" auf das Skript, bei dem der header()
Aufruf fehlgeschlagen ist.
Der Hinweis " Ausgabe gestartet um " in der Klammer ist wichtiger. Es bezeichnet die Quelle der vorherigen Ausgabe. In diesem Beispiel ist es auth.php
und Linie52
. Dort musste man nach vorzeitiger Ausgabe suchen.
Typische Ursachen:
Drucken, Echo
Durch die absichtliche Ausgabe von print
und echo
Anweisungen wird die Möglichkeit zum Senden von HTTP-Headern beendet. Der Anwendungsfluss muss umstrukturiert werden, um dies zu vermeiden. Verwenden Sie Funktionen
und Vorlagenschemata. Stellen Sie sicher, dass header()
Anrufe erfolgen, bevor 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
Nicht analysierte HTML-Abschnitte in einer .php
Datei werden ebenfalls direkt ausgegeben. Skriptbedingungen, die einen header()
Aufruf auslösen , müssen vor allen Rohblöcken notiert <html>
werden.
<!DOCTYPE html>
<?php
// Too late for headers already.
Verwenden Sie ein Vorlagenschema, um die Verarbeitung von der Ausgabelogik zu trennen.
- Platzieren Sie den Formularverarbeitungscode auf Skripten.
- Verwenden Sie temporäre Zeichenfolgenvariablen, um Nachrichten zu verschieben.
- Die eigentliche Ausgabelogik und die gemischte HTML-Ausgabe sollten zuletzt folgen.
Leerzeichen vor <?php
für "script.php Zeile 1 " Warnungen
Wenn sich die Warnung auf die Ausgabe in Zeile bezieht 1
, handelt es sich meistens um führende Leerzeichen , Text oder HTML vor dem öffnenden <?php
Token.
<?php
# There's a SINGLE space/newline before <? - Which already seals it.
Ebenso kann es bei angehängten Skripten oder Skriptabschnitten auftreten:
?>
<?php
PHP frisst tatsächlich einen einzelnen Zeilenumbruch nach dem Schließen von Tags auf. Es werden jedoch nicht mehrere Zeilenumbrüche, Tabulatoren oder Leerzeichen ausgeglichen, die in solche Lücken verschoben wurden.
UTF-8-Stückliste
Zeilenumbrüche und Leerzeichen allein können ein Problem sein. Es gibt aber auch "unsichtbare" Zeichenfolgen, die dies verursachen können. Am bekanntesten ist die
UTF-8-Stückliste (Byte-Order-Mark),
die von den meisten Texteditoren nicht angezeigt wird. Dies ist die Byte-Sequenz EF BB BF
, die für UTF-8-codierte Dokumente optional und redundant ist. PHP muss es jedoch als Rohleistung behandeln. Es kann als Zeichen 
in der Ausgabe (wenn der Client das Dokument als Latin-1 interpretiert) oder als ähnlicher "Müll" angezeigt werden .
Insbesondere grafische Editoren und Java-basierte IDEs sind sich ihrer Anwesenheit nicht bewusst. Sie visualisieren es nicht (verpflichtet durch den Unicode-Standard). Die meisten Programmierer und Konsoleneditoren tun jedoch Folgendes:
Dort ist das Problem leicht zu erkennen. Andere Editoren identifizieren möglicherweise das Vorhandensein in einem Datei- / Einstellungsmenü (Notepad ++ unter Windows kann das Problem identifizieren und
beheben ). Eine weitere Option zum Überprüfen des Vorhandenseins von Stücklisten besteht darin, auf einen Hexeditor zurückzugreifen . On * nix-Systeme hexdump
sind normalerweise verfügbar, wenn nicht eine grafische Variante, die die Prüfung dieser und anderer Probleme vereinfacht:
Eine einfache Lösung besteht darin, den Texteditor so einzustellen, dass Dateien als "UTF-8 (keine Stückliste)" oder eine ähnliche Nomenklatur gespeichert werden. Oft greifen Neulinge ansonsten dazu, neue Dateien zu erstellen und den vorherigen Code einfach wieder zu kopieren und einzufügen.
Korrekturdienstprogramme
Es gibt auch automatisierte Tools zum Überprüfen und Umschreiben von Textdateien ( sed
/awk
oder recode
). Für PHP gibt es speziell das phptags
Tag aufgeräumter . Es schreibt geschlossene und geöffnete Tags in lange und kurze Formulare um, behebt aber auch problemlos führende und nachfolgende Whitespace-, Unicode- und UTF-x-Stücklistenprobleme:
phptags --whitespace *.php
Es ist vernünftig, ein gesamtes Include- oder Projektverzeichnis zu verwenden.
Leerzeichen nach ?>
Wenn die Fehlerquelle hinter dem
Schließen?>
steht, wurde hier ein Leerzeichen oder Rohtext geschrieben. Der PHP-Endmarker beendet die Skriptausführung zu diesem Zeitpunkt nicht. Alle Text- / Leerzeichen danach werden weiterhin als Seiteninhalt ausgeschrieben.
Insbesondere Neulingen wird allgemein empfohlen, nachfolgende ?>
PHP-Close-Tags wegzulassen. Dies vermeidet einen kleinen Teil dieser Fälle. (Sehr häufig sind include()d
Skripte der Schuldige.)
Fehlerquelle als "Unbekannt in Zeile 0"
Es ist normalerweise eine PHP-Erweiterung oder eine php.ini-Einstellung, wenn keine Fehlerquelle konkretisiert wird.
- Es ist gelegentlich die
gzip
Stream-Codierungseinstellung
oder dieob_gzhandler
.
- Es kann sich aber auch um ein doppelt geladenes
extension=
Modul handeln, das eine implizite PHP-Start- / Warnmeldung generiert.
Vorhergehende Fehlermeldungen
Wenn eine andere PHP-Anweisung oder ein anderer Ausdruck dazu führt, dass eine Warnmeldung oder ein Hinweis ausgedruckt wird, gilt dies auch als vorzeitige Ausgabe.
In diesem Fall müssen Sie den Fehler vermeiden, die Ausführung der Anweisung verzögern oder die Nachricht mit zB isset()
oder @()
- unterdrücken,
wenn dies das spätere Debuggen nicht behindert.
Keine Fehlermeldung
Wenn Sie error_reporting
oder display_errors
deaktiviert pro php.ini
, dann zeigt keine Warnung auf. Das Ignorieren von Fehlern lässt das Problem jedoch nicht verschwinden. Header können nach vorzeitiger Ausgabe immer noch nicht gesendet werden.
Wenn header("Location: ...")
Umleitungen stillschweigend fehlschlagen, ist es sehr ratsam, nach Warnungen zu suchen. Aktivieren Sie sie mit zwei einfachen Befehlen über dem Aufrufskript erneut:
error_reporting(E_ALL);
ini_set("display_errors", 1);
Oder set_error_handler("var_dump");
wenn alles andere fehlschlägt.
Apropos Redirect-Header: Für endgültige Codepfade sollten Sie häufig eine solche Redewendung verwenden:
exit(header("Location: /finished.html"));
Vorzugsweise sogar eine Dienstprogrammfunktion, die bei header()
Fehlern eine Benutzermeldung druckt .
Ausgabepufferung als Problemumgehung
Die Ausgabepufferung von PHPs
ist eine Problemumgehung, um dieses Problem zu beheben . Es funktioniert oft zuverlässig, sollte jedoch die ordnungsgemäße Strukturierung der Anwendung und die Trennung der Ausgabe von der Steuerlogik nicht ersetzen. Der eigentliche Zweck besteht darin, die Übertragung von Chunks auf den Webserver zu minimieren.
Die output_buffering=
Einstellung kann trotzdem helfen. Konfigurieren Sie es in der php.ini
oder über .htaccess
oder sogar .user.ini in modernen FPM / FastCGI-Setups.
Durch Aktivieren kann PHP die Ausgabe puffern, anstatt sie sofort an den Webserver weiterzuleiten. PHP kann somit HTTP-Header aggregieren.
Es kann ebenfalls mit einem Aufruf zum ob_start();
Aufrufen des Aufrufskripts verbunden werden. Was jedoch aus mehreren Gründen weniger zuverlässig ist:
Selbst wenn <?php ob_start(); ?>
das erste Skript gestartet wird, werden Leerzeichen oder Stücklisten möglicherweise zuvor gemischt, wodurch es unwirksam wird .
Es kann Leerzeichen für die HTML-Ausgabe verbergen. Sobald die Anwendungslogik jedoch versucht, binären Inhalt (z. B. ein generiertes Bild) zu senden, wird die gepufferte Fremdausgabe zu einem Problem. (Notwendig ob_clean()
als weitere Problemumgehung.)
Der Puffer ist in seiner Größe begrenzt und kann leicht überlaufen, wenn die Standardeinstellungen beibehalten werden. Und das ist auch keine Seltenheit, schwer zu finden,
wenn es passiert.
Beide Ansätze können daher unzuverlässig werden - insbesondere beim Wechsel zwischen Entwicklungs-Setups und / oder Produktionsservern. Aus diesem Grund wird die Ausgabepufferung allgemein nur als Krücke / strikte Problemumgehung betrachtet.
Siehe auch das grundlegende Verwendungsbeispiel
im Handbuch und weitere Vor- und Nachteile:
Aber es hat auf dem anderen Server funktioniert!?
Wenn Sie die Header-Warnung zuvor nicht erhalten haben, wird die Einstellung php.ini für die Ausgabepufferung verwendet
geändert. Es ist wahrscheinlich auf dem aktuellen / neuen Server nicht konfiguriert.
Überprüfen mit headers_sent()
Sie können jederzeit headers_sent()
prüfen, ob es noch möglich ist, ... Header zu senden. Dies ist nützlich, um eine Information bedingt auszudrucken oder eine 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 Fallback-Problemumgehungen sind:
HTML- <meta>
Tag
Wenn Ihre Anwendung strukturell schwer zu reparieren ist, können Sie auf einfache (aber etwas unprofessionelle) Weise, um Weiterleitungen zuzulassen, ein HTML-
<meta>
Tag einfügen. Eine Weiterleitung kann erreicht werden mit:
<meta http-equiv="Location" content="http://example.com/">
Oder mit kurzer Verzögerung:
<meta http-equiv="Refresh" content="2; url=../target.html">
Dies führt zu ungültigem HTML, wenn es nach dem <head>
Abschnitt verwendet wird. Die meisten Browser akzeptieren es immer noch.
JavaScript-Umleitung
Alternativ kann eine JavaScript-Umleitung
für Seitenumleitungen verwendet werden:
<script> location.replace("target.html"); </script>
Dies ist häufig HTML-kompatibler als die <meta>
Problemumgehung, erfordert jedoch JavaScript-fähige Clients.
Beide Ansätze machen jedoch akzeptable Fallbacks, wenn echte HTTP-Header () -Aufrufe fehlschlagen. Idealerweise kombinieren Sie dies immer mit einer benutzerfreundlichen Nachricht und einem anklickbaren Link als letzten Ausweg. (Welches ist zum Beispiel das, was der http_redirect ()
PECL-Erweiterung tut.)
Warum setcookie()
undsession_start()
sind auch betroffen
Beide setcookie()
und session_start()
müssen eine sendenSet-Cookie:
HTTP-Header . Es gelten daher die gleichen Bedingungen, und für vorzeitige Ausgabesituationen werden ähnliche Fehlermeldungen generiert.
(Natürlich sind sie außerdem von deaktivierten Cookies im Browser oder sogar von Proxy-Problemen betroffen. Die Sitzungsfunktionalität hängt natürlich auch vom freien Speicherplatz und anderen php.ini-Einstellungen usw. ab.)
Weitere Links