9

I want to force user to download images. Not open in browser.

It is possible to use HTML5 this attribute download but currently only Chrome supports it.

I tried .htaccess solution but it doesn't work.

<Files *.jpg>
   ForceType application/octet-stream
   Header set Content-Disposition attachment
</Files>

How can I force download all my images if user click on the link ?

<a href="http://blablabla.com/azerty/abc.jpg" target="_blank" />Download</a>
hakre
  • 193,403
  • 52
  • 435
  • 836
Steffi
  • 6,835
  • 25
  • 78
  • 123
  • how about double quoting `"attachment"` – Adi Jun 18 '12 at 20:10
  • @AdnanShammout: This really isn't going to change anything. – netcoder Jun 18 '12 at 20:12
  • then I think you should make sure `mod_headers` is uncommented in your `php.ini` – Adi Jun 18 '12 at 20:14
  • All I know is that it works. Double check your webserver configuration and if you don't feel able to, contact the technical personel that normally takes care of that (your sysadministress), see as well [`ForceType` Directive](http://httpd.apache.org/docs/current/mod/core.html#forcetype) and [`Header` Directive](http://httpd.apache.org/docs/current/mod/mod_headers.html#header). – hakre Oct 19 '13 at 12:29

2 Answers2

14

There's two ways to do this - one with JS, one with PHP.

In JS from this site:

<a href="javascript:void(0);"
 onclick="document.execCommand('SaveAs',true,'file.html');"
 >Save this page</a>

In PHP create a script named download.php that is similar to the following code:

<?php
// Force download of image file specified in URL query string and which
// is in the same directory as the download.php script.

if(empty($_GET['img'])) {
   header("HTTP/1.0 404 Not Found");
   return;
}

$basename = basename($_GET['img']);
$filename = __DIR__ . '/' . $basename; // don't accept other directories

$mime = ($mime = getimagesize($filename)) ? $mime['mime'] : $mime;
$size = filesize($filename);
$fp   = fopen($filename, "rb");
if (!($mime && $size && $fp)) {
  // Error.
  return;
}

header("Content-type: " . $mime);
header("Content-Length: " . $size);
// NOTE: Possible header injection via $basename
header("Content-Disposition: attachment; filename=" . $basename);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
fpassthru($fp);

Then set the image link to point to this file like this:

<img src="/images/download.php?img=imagename.jpg" alt="test">
hakre
  • 193,403
  • 52
  • 435
  • 836
SickHippie
  • 1,382
  • 1
  • 8
  • 20
  • 2
    JS approach is not working in FF and Chrome, you need to modify .htaccess: http://stackoverflow.com/questions/833015/does-execcommand-saveas-work-in-firefox – peter.o Oct 10 '12 at 12:38
  • 1
    Since this was marked correct months ago, why would you come here and say it's wrong now? The question you linked to has incorrect JS syntax - the 2nd parameter needs to be boolean true, not string 'true'. – SickHippie Oct 17 '12 at 18:24
  • execCommand for that case is IE specific and non-standard - http://msdn.microsoft.com/en-us/library/ms536419(v=vs.85).aspx - From the light of the question it is clear that the OP asks for a cross-browser compatible specification. - Then you do not explain why (or why not) the .htaccess as outlined in the question didn't make it. Instead it's just an additional way to do something and I bet that has been better answered earlier but you're not providing even reference to that. Not to say the code could be greatly improved for readability as well. – hakre Oct 19 '13 at 11:46
  • So, even though what I wrote worked for OP months ago, you rewrote the php almost entirely and removed the reference to where I picked it up from. On top of that, YOU REWROTE OP'S QUESTION. Then you make assumptions ("I bet that has been better answered...") without bothering to look yourself to see if you're actually right. Wow. – SickHippie Oct 21 '13 at 06:04
-2

Try this in your .htaccess instead:

<FilesMatch "\.(?i:jpg|gif|png)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>
Sebastian Piskorski
  • 4,026
  • 3
  • 23
  • 29