In bestimmten Fällen ist es erwünscht, dass ein PHP-Skript die von ihm erzeugten Daten nicht einfach in Form einer HTML-Seite ausgibt, sondern sie an den Client sendet. Dieser sollte diese in Form einer Datei speichern oder an andere Applikationen übergeben.
Solche Fälle tauchen vorwiegend bei Anhängen (Attachments) in einem Webmail-System auf. Normalerweise wird die Ausgabe eines PHP-Skripts als HTML interpretiert, das der Browser darstellt. Damit der Browser die Datei jedoch speichert, muss die Angabe über den Typ des Dateiinhalts für die Übertragung geändert werden. Hierfür stehen Ihnen Content-Type und Content-Disposition zur Verfügung:
header("Content-Type: application/octetstream");
Soweit nichts anderes angegeben wird, benutzt der Browser den Dateinamen des PHP-Skripts aus der URL als Dateinamen zum Abspeichern.
header("Content-Disposition: attachment; filename=dateiname.ext");
Mit diesem Header wird der Dateiname auf dateiname.ext gesetzt. Sie sollten vor allem darauf achten, dass keine Quoting-Zeichen wie etwa Hochkommata vorkommen. Grund hierfür ist, dass bestimmte Browser wie der Internet Explorer sonst die Quoting-Zeichen als Teil des Dateinamens interpretieren.
Achtung: Eventuelle Pfadangaben werden übrigens ignoriert, d. h., es ist möglich den Dateinamen festzulegen, aber nicht, in welches Verzeichnis die Datei gespeichert werden sollte.
Problematik mit Internet Explorer
Microsoft verarbeitet die RFCs scheinbar anders als alle anderen Browser, sodass der IE 5.5 nur folgenden Header versteht:
header("Content-Disposition: filename=dateiname.ext");
Über die Variable $HTTP_USER_AGENT können Sie PHP auch entscheiden lassen, welche Variante wahrscheinlich die richtige ist.
header("Content-Disposition: ".(strpos($HTTP_USER_AGENT,"MSIE 5.5")?"":"attachment;")."filename=dateiname.ext");
Nachteil der Header-Methode
Die Methode, den Dateinamen über den Header festzulegen, hat jedoch einen kleinen Nachteil: Sollte der Anwender später im Browser nicht auf den Link klicken, um dann die Datei zu speichern, sondern direkt über Save Link as speichern, konnte noch kein Header gesendet werden, sodass der Browser den Dateinamen nicht kennt und wieder den Dateinamen des Skripts vorschlägt. Das kann nur umgangen werden, indem man dafür sorgt, dass der gewünschte Dateiname in der URL steht. Dies ist wiederum nur über Funktionen des Webservers möglich. Beim Apache sind das die Funktionen Rewrite und Redirect.
Die Erfahrung hat gezeigt, dass ein Content-Transfer-Encoding-Header die ganze Sache sicherer macht, auch wenn er laut RFC 2616 nicht benutzt wird.
header("Content-Transfer-Encoding: binary");
Die meisten Browser zeigen beim Download häufig einen Fortschrittsbalken an. Dies funktioniert allerdings nur dann, wenn der Browser weiß, wie groß die Datei ist. Die Größe der Datei in Byte wird über den Content-Length-Header angegeben.
header("Content-Length: {Dateigrösse}");
Zusammenfassend können wir nun folgenden Header benutzen, wenn die Ausgabe eines Skripts heruntergeladen werden soll:
<?php
// Dateityp, der immer abgespeichert wird
header("Content-Type: application/octetstream");
// Dateiname mit Sonderbehandlung des IE 5.5
header("Content-Disposition: ".(!strpos($HTTP_USER_AGENT,"MSIE 5.5")?"attachment; ":"")."filename=datei name.ext");
// Im Grunde ueberfluessig, hat sich anscheinend bewährt
header("Content-Transfer-Encoding: binary");
// Zwischenspeichern auf Proxies verhindern
header("Cache-Control: post-check=0, pre-check=0");
// Dateigröße für Downloadzeit-Berechnung
header("Content-Length: {Dateigroesse}");
?>
Hinweis: Diese Headerkombination sollte zuverlässig funktionieren. Bei der Vielzahl von Browsern, die sich nicht immer an die RFCs halten, ist jedoch nicht ausgeschlossen, dass diese Kombination angepasst werden muss.
|