X-Sendfile
Wer kennt sie nicht, die Probleme beim Download grosser Dokumente, die nicht per statischer URL erreichbar sind?
Gründe, wieso Dokumente nicht direkt vom Webserver ausgeliefert werden bzw. sich sogar ausserhalb des öffentlichen Bereiches befinden, gibt es einige. Sei es zum Schutz vor unbefugtem Download oder einfach nur für die Statistik. Auf jeden Fall muss eine aktive Komponente dazwischen geschaltet werden.
In unserem Fall handelt es sich dabei um PHP.
Mit der Funktion readfile lässt sich das auch im Normalfall ohne Probleme bewerkstelligen.
Rein theoretisch liest PHP 8K chunks in den Speicher und flushed diese dann auch direkt an den Browser. Memory-Overflow, Timeouts oder ähnliches sollten daher eigentlich kein Problem darstellen. Und trotzdem kommt es, vor allem bei grösseren Dokumenten, immer wieder zu fehlerhaften Donwloads.
Bei meiner Recherche im Web bin ich dann auf ein vielversprechendes Apache-Module namens XSendFile gestossen.
XSendFile verarbeitet X-SENDFILE Headers, die z.B. per PHP gesetzt werden und liefert dann das gewünschte Dokument über die internen Funktionen des Apache Webserver aus. D.h. es ist kein Einlesen des Dokumentes per PHP in den Speicher nötig. Apache kümmert sich selbst um den Download mit sämtlichen Vorteilen wie z.B. optimale Auslieferung durch sendfile und mmap (falls vorhanden), korrekte Cache-Header wie Etag und If-Modified-Since, als ob die Datei statisch ausgeliefert wird.
isLoggedIn()) { $file = '/var/www/massiveart.com/secure/report.pdf'; if (file_exists($file)) { header('X-Sendfile: ' . $file); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); exit; } }Das Module zu installieren ist eine Kleinigkeit und hat bei uns ein Problem gelöst, welches wir zunächst nicht nachvollziehen konnten.
Hier noch eine kurze Anleitung wie das Module für Ubuntu Server kompiliert und aktiviert werden kann:
wget https://tn123.org/mod_xsendfile/mod_xsendfile-0.12.tar.gz --no-check-certificate // entpacken tar -zxvf mod_xsendfile-0.12.tar.gz cd mod_xsendfile-0.12 // kompilieren apxs2 -cia mod_xsendfile.c // Apache Module Load-File erstellen echo "LoadModule xsendfile_module /usr/lib/apache2/modules/mod_xsendfile.so" >> /etc/apache2/mods-available/xsendfile.load // Module aktivieren a2enmod xsendfileJetzt muss die Erweiterung nur noch für den gewünschten VirtualHost aktiviert werden.
ServerName www.massiveart.com DocumentRoot /var/www/massiveart.com/public XSendFile on XSendFilePath /var/www/massiveart.com/secure Apache neu starten und schon läuft das Module.