5

So I have a downloads page where you click a link, it opens /downloads/download/randomhash

randomhash is found in the db, i increment a download counter, and then redirect to the actual file e.g. /uploads/2012/file.png.

Everything works except for the redirect doing what I'd like it to do. I'm not sure why it's not working...

  header("Location: " . $row->uri);
  header("Content-Disposition: attachment; filename=$row->name");

On the first load of the file, it has the appropriate content-disposition header (in firebug), but it doesn't prompt the file to be downloaded (which it should, right??). Any ideas?

Response Headers:

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0, public
Connection: Keep-Alive
Content-Disposition: attachment; filename=promotion_photo_2.jpg
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html; charset=utf-8
Date: Mon, 27 Feb 2012 01:01:22 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=100
Location: /uploads/2012/mediakitD3CF.jpg
Pragma: no-cache
Server: *
Vary: Accept-Encoding
X-Powered-By: *
X-UA-Compatible: IE=Edge,chrome=1
Benno
  • 3,008
  • 3
  • 26
  • 41
  • 1
    you should redirect to a download controller that will handle the appropriate headers, currently your just adding the Content-Disposition header to the redirect header – Lawrence Cherone Feb 27 '12 at 01:08

1 Answers1

4

You are setting the Content-Disposition header in the same response which tells the browser where to redirect. My suggestion is to just stream the attachment on the response, with no redirect

header('Content-Disposition: attachment; filename=file-to-be-downloaded.jpg');
header('Content-type: image/jpeg'); // or what is relevant, ie application/octet-stream
$fn=fopen("path-to-file/file-to-be-downloaded.jpg","r");
fpassthru($fn);
guido
  • 18,864
  • 6
  • 70
  • 95
  • 2
    How will that go with ~ 300mb movie files :\? I originally had something similar to this using file_get_contents but PHP ran out of memory trying to buffer 300mb of the contents to the browser... lol. My other thought was conditionally setting headers in my apache configuration for anything in uploads, but not sure how to do that (can't do a 'RewriteCond' and Header set or FilesMatch...) – Benno Feb 27 '12 at 01:18
  • sorry, you just put a jpg image in your question; for larger downloads, read the 4th comment here: http://php.net/manual/en/function.fpassthru.php or use http://pear.php.net/manual/en/package.http.http-download.intro.php – guido Feb 27 '12 at 01:27
  • You're really suggesting to proxy the entire file through your webserver with fpassthru? Not only would this get you blocked possibly, but it would likely be deducted from allotted bandwidth to your site. – NoBugs Jan 19 '18 at 04:39
  • Bandwidth might be an issue. When you store your file with Amazon AWS with "anonymized" names and have the original file name in your database. When you want to offer a download the user should be redirected to Amazon. `fpassthrough` or the like would download the file from Amazon to your webserver and would send it in a second step to the client. – Bernhard Döbler Mar 06 '18 at 09:13
  • @NoBugs and Bernard your comments are not relevant for this question: he is asking how to have his users download a file stored in his server storage; the URI to the file would be a local path. What fpassthru is doing here is just piping a reader of a file descriptor into an http connection. If the resource is stored in a third party location, you will need to redirect to a controller there, or inject the http header in the web server, to be able to set Content-Disposition, as setting it in the redirect http response will have zero effect. – guido Mar 06 '18 at 18:20
  • @ᴳᵁᴵᴰᴼ It does seem unfortunate that making a proxy through is the only way to add the header. :/ – NoBugs Mar 08 '18 at 02:52