45

I am currently working on a PHP script that allows you to download media contents (video, audio, pictures...) from your mobile device by accessing a link. (i.e. http://www.my-web-site.com/download.php?id=7ejs8ap) My script worked very vell when I was testing it with recent mobile (Samsung Galaxy S, iPhone 4S, some others...) but an error occured on my old mobile Samsung C3050. The media I wanted to download was just an audio mp3 file that I usually download easily.

The error appears to be "Unknown content type." So, as my only HTTP header Content-Type was "application/force-download", I try to comment this and try again. Then, it works. But now, I am currently asking what this Content-Type means and if it can be mandatory for others mobile. I tested without the Content-Type on the iPhone 4 and it works, but I'm not sure of this compatibility for all mobile.

Can someone explain me how that Content-Type works, why this isn't a standard MIME or everything else that can help me to be sure this is an optionnal Content-Type for every download, whatever the file, the browser or the device I am downloading on?

Thanks everyone.

Here is my PHP headers sent:

<?php
//Assume that $filename and $filePath are correclty set.
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="'.$filename.'"');
// header('Content-Type: application/force-download'); Non-standard MIME-Type, incompatible with Samsung C3050 for example. Let it commented
readfile($filePath);
?>

EDIT : I just tried with a Sony Xperia, and the download wasn't successful: I only see the "html-encoded" bytes of my file I want to download. How can I know what content-type I have to use if application/octet-stream or application/force-download doesn't work?

niconoe
  • 1,100
  • 1
  • 11
  • 25

3 Answers3

128

Content-Type: application/force-download means "I, the web server, am going to lie to you (the browser) about what this file is so that you will not treat it as a PDF/Word Document/MP3/whatever and prompt the user to save the mysterious file to disk instead". It is a dirty hack that breaks horribly when the client doesn't do "save to disk".

Use the correct mime type for whatever media you are using (e.g. audio/mpeg for mp3).

Use the Content-Disposition: attachment; etc etc header if you want to encourage the client to download it instead of following the default behaviour.

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
  • Thank you for your explanations. I'll try later the application/octet-stream and if it doesn't work, I'm gonna use a function to detect the mime-type from a filename. I hope this will work for some "special" file I have like *.m4r or *.dm for special iPhone ringtones for example... If not, I will do my own unwanted switch/case :'( – niconoe May 16 '12 at 11:05
  • @nioconoe The easiest way to figure out a mime type for a file is to the fileinfo library. In PHP, it is http://www.php.net/manual/en/function.finfo-file.php. You can also run `file --mime ` from a command line. – Mark E. Haase Oct 23 '12 at 19:26
  • What if the content itself is an html page? ( example an html report ) ? – D34dman Apr 22 '13 at 15:08
  • @Quentin thanks for clarifying :) i was generating an html report (and a much better report was already being displayed on the screen). So there is this download link on this page and i asked myself, does the user really have to confirm it before saving it to disk! isn't that an un-necessary step. So its a dirty thing to do it seems. And i don't want my application to be labelled a liar :). Should be careful about simplifying workflow and stuff. – D34dman Apr 22 '13 at 18:52
  • @Quentin I feel sort of proud here, awarding you the 100 up-vote and a gold badge, good answer! – Eugene Mar 01 '18 at 09:54
16

To download a file please use the following code ... Store the File name with location in $file variable. It supports all mime type

$file = "location of file to download"
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);

To know about Mime types please refer to this link: http://php.net/manual/en/function.mime-content-type.php

catfood
  • 3,896
  • 3
  • 27
  • 49
Suresh kumar
  • 1,822
  • 1
  • 18
  • 28
  • Although this function is deprecated, I can read some explanations on MIME-type, so thank you. But, it doesn't explain me why application/force-download is not a recognized content-type for all browsers... – niconoe May 16 '12 at 10:27
  • 12
    Content-Description does not exist in HTTP. Content-Transfer-Encoding does not exist in HTTP. (See http://www.iana.org/assignments/message-headers/perm-headers.html). All of the cache related headers are probably useless. Finally, the Content-Disposition header will be invalid for many values of $file. See RFC 6266. – Julian Reschke May 16 '12 at 12:03
  • Suresh, the mime_content_type function is now considered deprecated. – catfood Nov 05 '13 at 14:10
  • Question: why are you using flush() and ob_clean() – Jabran Saeed May 22 '14 at 10:14
  • As said elsewhere : prefer using the real Content-Type, not "Content-Type: application/octet-stream". – Pierre-Olivier Vares Oct 12 '15 at 09:42
  • I was having issues downloading in .Net and using these headers in this order helped me solve the problem where other examples failed. Thanks! – user1532208 Jan 06 '16 at 20:55
4

application/force-download is not a standard MIME type. It's a hack supported by some browsers, added fairly recently.

Your question doesn't really make any sense. It's like asking why Internet Explorer 4 doesn't support the latest CSS 3 functionality.

Jon Grant
  • 10,975
  • 2
  • 33
  • 54
  • I know that it's not a standard MIME type, but I didn't know it was added recently. I unsertand you telling me my question doesn't make any sense, but why, when I tried with my Sony Xperia without this "Content-Type hack", it doesn't work anymore? It seems this will be used for our browsers which dislike work with standard... – niconoe May 16 '12 at 11:08
  • 4
    Because by definition when you use a non-standard content type, the implementation is undefined. Anything the browser does is technically "correct". You could just as easily set the content type to "application/sadjkfhlaksdjdkfjgh" and achieve the exact same effect. – Jon Grant May 16 '12 at 11:55