donderdag, juni 21, 2007

correct file downloads

LET OP TECHNISCH VERHAAL!.

Voor mijn eigen simpel content management (zo simpel, je mag het geen CMS meer noemen!, binnenkort meer daarover.) heb ik een script nodig om files correct te kunnen downloaden. Het idee is namelijk dat ik meerdere sites via dezelfde scripts wil publiceren. Zo kan ik www.domein1.nl en www.domein2.nl via dezelfde database en server laten lopen. En dat is geen probleem. Met wat scripten is dat zo opgelost

Het enige probleem wat je dan hebt zijn bestanden. Ik wil namelijk gewoon bestanden kunnen aanroepen via www.domein1.nl/main.css en www.domein2.nl/main.css. En toch moeten het verschillende bestanden zijn. Daarnaast moeten alle soorten bestanden van alle mogelijke mimetypes mogelijk zijn en moeten ze correct worden weergeven.

Nu is het geen probleem om alle aanvragen voor files door 1 bestand te laten afhandelen bijvoorbeeld: file.php. Door het mime-type correct te zetten weet de browser ook hoe hij het af moet handelen. 1 nadeel: als je het bestand wilt opslaan zal het de naam "file.php" krijgen. En dat wil je eigenlijk niet. Je wilt gewoon de originele naam gebruiken. Na wat zoeken kwam ik op de volgende extra header die je mee kunt sturen: Content-disposition (zie rfc) de content disposition is bedoeld om meer metadata weer te kunnen geven over de geleverde content.

Een hele nuttige optie is:
header("Content-disposition: inline; filename=" . $fileName);

waarmee je ervoor kunt zorgen dat een filename goed weergegeven wordt bij het downloaden of opslaan in de browser.
header("Content-disposition: attachment; filename=" . $fileName);
kun je gebruiken als je ervoor wilt zorgen dat er altijd een download box getoond wordt. Het heeft mij even uitzoek werk gekost (voor de 2e keer, ik heb het al ooit gebouwd in ASP.NET) en nu wil ik het nooit meer vergeten!

Op naar de volgende uitdaging!

2 opmerkingen:

Anoniem zei

Voor onze lieve vriendjes van Campina ben ik het nog iets eleganter ana het implementeren. En cross-browser/platform.
Er zijn wat restrcties, zo moet je bijv geen spaties toestaan in de files. Daarnaast moeten de headers er zo uit zien(gedeelte met dank aan Jakob van Sitecore). Let vooral op het downloadtype:

(C#)
//Clear all headers to make sure any others are sent to the client
Headers.Clear();

//Sent the force download type to your client
Headers.Add("Content-Type", "application/force-download");

//Pass the right username
Headers.Add("Content-Disposition", "attachment; filename=" + filename);

//Add the length of the file in bytes
Headers.Add("Content-Length", bytes);

//Make the client aware of the binary stream
Headers.Add("Content-Transfer-Encoding", "binary");

Hans van Leuken zei

Je hebt gelijk voor binaire files. Ik wil echter ook text files via dit script kunnen doen.

overigens is er veel discussie over contenttype "application/force-download". aangeraden wordt om: header("Content-Type: application/octet-stream"); te gebruiken.

quote: If you wish to force a file to be downloaded and saved, instead of being rendered, remember that there is no such MIME type as "application/force-download". The correct type to use in this situation is "application/octet-stream", and using anything else is merely relying on the fact that clients are supposed to ignore unrecognised MIME types and use "application/octet-stream" instead (reference: Sections 4.1.4 and 4.5.1 of RFC 2046).
#end quote

Verder lees ik de mime.config uit voor correcte mime types en moet je inderdaad de content-length goed gebruiken. Maar als het werkt dan werkt het ;)

Ik heb nog niet getest met filenames met spaties dat is een goede tip :)