4

I am forcing the download of an image through my website.

Forced download works fine on Apache/Windows development machine.

However it pushes junk characters to the screen when live on my linux web server.

e.g. �����JFIF��H�H����6Exif��MM�*����
  • Firefox - junk
  • Chrome - junk
  • Internet Explorer 7 - displays the image in the page

    $fileName = basename($filePath);
    $fileSize = filesize($filePath);
    
    
    // Output headers.
    header("Cache-Control: private");
    header("Content-Type: Image/jpeg");
    header("Content-Length: ".$fileSize);
    header("Content-Disposition: attachment; filename=".$fileName);
    
    
    // Output file.
    readfile ($filePath);                   
    exit();
    

What differences might there be on my live server that would cause it to break?

Jon Winstanley
  • 23,010
  • 22
  • 73
  • 116
  • question, you want to force download yet to open the file in browser ? try download the file first, and open with image editing tools to check return file is valid – ajreal Nov 25 '10 at 10:20
  • I think you meant [application/octet-stream](http://tools.ietf.org/html/rfc2046#section-4.5.1). – Gumbo Nov 25 '10 at 10:25
  • I have changed my content type to Image/Jpeg but still get the same issue – Jon Winstanley Nov 25 '10 at 10:34
  • See stillstanding's response below; using fifo you can automatically detect the correct mime type, which will make your life easier. – El Yobo Nov 25 '10 at 12:32
  • Try lowercase `image/jpeg`. I've never seen a mixed-case MIME type. – TRiG Mar 29 '13 at 13:56

3 Answers3

5

Hat tip (and +1) to stillstanding, who pointed out using fifo, but I thought I'd provide an example here to help. This example requires the fifo extension installed, and has been hacked out and slightly modified from some other code of mine.

    $filename = 'blarg.jpg';
    $filepath = '/foo/bar/blarg.jpg';
    $finfo    = new finfo(FILEINFO_MIME);
    $mime     = $finfo->file($file);

    // Provide a default type in case all else fails
    $mime = ($mime) ? $mime : 'application/octet-stream';

    header('Pragma: public');
    header('Content-Transfer-Encoding: binary');
    header('Content-type: ' . $mime);
    header('Content-Length: ' . filesize($filepath));
    header('Content-Disposition: attachment; filename="' . $filename . '"');

    header('Content-transfer-encoding: 8bit');
    header('Expires: 0');
    header('Pragma: cache');
    header('Cache-Control: private');
Community
  • 1
  • 1
El Yobo
  • 14,823
  • 5
  • 60
  • 78
  • 1) There's no point in providing a default Content-Type. If you don't know it, leave it out. 2) There's no Content-Transfer-Encoding header in HTTP. 3) The Content-Disposition header will be illegal as soon as the the filename contains characters outside ISO-8859-1. See RFC2231/5987 for additional advice. – Julian Reschke Nov 25 '10 at 17:46
  • Thanks, will check that out. Is there any suggested method for handling non ISO-8859-1 characters? I just use this approach to encourage the browser to download images and videos, rather than displaying them inline. Also, what is the downside to providing application/octet-stream as the default? – El Yobo Nov 25 '10 at 21:39
  • The recommended encoding for filename is described in RFC5987 and draft-ietf-httpbis-content-disposition (but it doesn't work in all browsers). A default of application/octet-stream is meaningless; there's no point to set it if you don't know the real encoding. – Julian Reschke Nov 26 '10 at 09:55
2

You have an incorrect MIME type in the header. Use finfo so you can send the correct one instead of transmitting everything as an application/stream, otherwise browser behavior will be unpredictable.

bcosca
  • 17,371
  • 5
  • 40
  • 51
1

Shouldn't the Content-Type be set to image?

Jim
  • 22,354
  • 6
  • 52
  • 80