Hauptmenü

Untermenü

PHP/MySQL - Header - Downloads

1. Die Abschnitte

2. Zwang

Manchmal kann es passieren, dass man einen direkten Download erzwingen möchte. Ein wunderbares Beispiel dafür sind JPEG-Bilder, die im CMYK-Format abgespeichert worden sind. Denn damit kommen die meisten Browser nicht klar, da es vor allem im DTP-Bereich eingesetzt wird.

Bietet man also zum Beispiel eine Bilddatenbank mit CMYK-JPEGs an, so darf man die nicht einfach verlinken. Nein, man setzt einen Link auf eine PHP-Datei, die dann die Arbeit übernimmt. Öffnet dazu im Ordner downloads mal die Datei download.htm. Dort setzen wir den Anker mittels <a href="bilder_cmyk.php">Bild</a>.

3. Der Download

... findet in der oben erwähnten bilder_cmyk.php statt. Der Einfachheit halber arbeiten wir mal ohne GET-Parameter, sondern nehmen einfach ein "hartkodiertes" Bild. Der Code selber sieht so aus:


<?php
  $jpg  file_get_contents('moi_cmyk.jpg');
  $size filesize('moi_cmyk.jpg');  
  header('Content-Disposition: attachment; filename=moi_cmyk.jpg');
  header('Content-type: application/force-download');
  header('Content-Length: '.$size);  
  header('Content-type: application/octetstream');
  echo $jpg;
?>

Erläuterung

Mit $jpg = file_get_contents('moi_cmyk.jpg'); lesen wir wie gehabt das Bild ein und mit $size = filesize('moi_cmyk.jpg'); ermitteln wir die Dateigröße. Zu Letzterem komme ich später.

Den Download erzwingen

Das geschieht über header('Content-Disposition: attachment; filename=moi_cmyk.jpg');. Allerdings führt das dazu, dass bei einem vorgegebene Download-Verzeichnis (zum Beispiel im Firefox möglich) das Bild einfach dort abgespeichert wird. Mit header('Content-type: application/force-download'); "zwingt" man den Browser dazu, ein entsprechendes Dialogfeld zu öffnen. Das ist allerdings abhängig von den dortigen Einstellungen. So bietet Firefox zum Beispiel an, ob man die Datei speichern oder mit einem entsprechenden Programm öffnen möchte.

Zusatzinfos

Bei größeren Dateien ist es immer ganz gut, wenn der Browser weiß, wie viel er herunterladen muss. Dann kann er nämlich die Download-Zeit einigermaßen präzise berechnen. Und da wir die ja schon mit $size = filesize('moi_cmyk.jpg'); errechnet haben, senden wir sie mittels header('Content-Length: '.$size);.

Und was soll das header('Content-type: application/octetstream');? Ist das nicht überflüssig? Eigentlich ja, aber das ist eine der Merkwürdigkeiten, die uns immer wieder begegnen. Denn jeder Browser reagiert anders und manchmal muss man mit dezenten Hinweisen oder roher Gewalt arbeiten, damit es auch so funktioniert, wie wir wollen. Obiger Code zum Beispiel war noch vor Jahren nötig, damit der Internet Explorer für Mac(!) damit klar kam.

Leere Seite?

Viele Anfänger denken oft, dass bei einem Klick auf den Link erst die Seite bilder_cmyk.php aufgerufen wird. Dann erscheint eine leere Seite und dann kommt der Download-Dialog. Falsch! Zuerst sendet der Server die entsprechenden Header und dann erst(!) entscheidet der Browser, wie er damit umgeht. In diesem Fall sagt er sich

"Kenn isch net, will isch net, fort damit" [Quelle: Ein Browser]

und überlässt dem Anwender die Entscheidung. Das bedeutet auch, dass er die angeforderte Seite bilder_cmyk.php nicht im Browserfenster lädt! Praktisch, gell?

4. Noch mehr Feinheiten

Bei obigem Beispiel mit einem CMYK-JPEG mussten wir schon etwas Aufwand treiben, damit es funktioniert. Das liegt daran, dass Browser von Hause aus mit (RGB)-JPEGs umgehen können. Anders sieht es zum Beispiel mit einem PDF (pdf.php) aus. Da reicht im Normalfall schon dieser Code aus.


<?php
  $pdf  file_get_contents('test.pdf');
  $size filesize('test.pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  header('Content-Length: '.$size);  
  echo $pdf;
?>

Klickt mal in der download.htm auf den entsprechenden Link.

5. Ein Tipp

Spielt mal mit den Headern und diversen Browsern mit unterschiedlichen Einstellungen herum. Dann werdet ihr auch sehr schnell lernen, dass jeder Browser anders reagiert. Arbeitet auch ruhig mal mit anderen Dateitypen und den entsprechenden Headern. Schaden kann es auf keinen Fall.

zurück zum vorherigen Abschnitt weiter zum nächsten Abschnitt