views:

259

answers:

3

I have a directory of images that alternately be viewed directly in the browser, and other times downloaded.

So, say I have a file /gallery/gal_4254.jpg.

I want to make /download/gal_4254.jpg trigger a download of the image rather than view it. /download is empty, all the images are in /gallery.

I can map requests to the download dir to the other files successfully

<Directory /var/www/download>
    RewriteEngine on
    RewriteRule (.*)$ /gallery/$1
</Directory>

and I already can force downloads in the gallery dir by setting

<Directory /var/www/gallery/>
    ForceType "image/jpg"
    Header set Content-Disposition "attachment"
</Directory>

so setting the headers is no problem. I don't actually want /gallery to have the headers though, just requests for /gallery/* through /download/ that are rewritten.

But, I need to combine the two, so the request is mapped to the file in the other dir AND the file is given the attachment header.

#does not work - just views the image like when it is viewed directly
<Directory /var/www/download>
    ForceType "image/jpg"
    Header set Content-Disposition "attachment"
    RewriteEngine on
    RewriteRule (.*)$ /gallery/$1
</Directory>

I've tried changing the order of the rewrite and header sections to no avail. I think it loses the header when the request is rewritten to the other directory.

Any suggestions on how to do this in Apache?

I realize this could be done with PHP as well, which is why I posted it here vs. Server Fault. A solution using PHP would be welcome also.

+2  A: 

A combined solution could be the following setup. First change the directory entry:

<Directory /var/www/download>
    RewriteEngine on
    RewriteRule (.*)$ download.php?getfile=$1
</Directory>

The download.php should contain something like this (NOT TESTED):

<?php

if ($_GET['getfile']){
  $file = '/var/www/gallery/' . $_GET['getfile'];
}

$save_as_name = basename($file);   
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: no-cache');
header("Content-Type: application/octet-stream");
header("Content-Disposition: disposition-type=attachment; filename=\"$save_as_name\"");

readfile($file);
?>

This shouldd redirect all download requests to download.php which in turn handles the requests and forces the saveas dialog to appear.

Paul

Paul
Thanks! Since you and xaoc gave about the same answer 2 minutes apart, I flipped a coin and xaoc got the acceptance. You do nonetheless have my appreciative upvote.
Alex JL
+2  A: 

Simple php solution:

download.php

header('Content-Type: image/jpeg');
header('Content-Disposition: attachment; filename='.$_GET['img']);
readfile('gallery/'.$_GET['img']);

.htaccess

<Directory /var/www/download>
    RewriteEngine on
    RewriteRule (.*)$ /download.php?img=$1
</Directory>
xaoc
+1  A: 

I just did this, after stumbling on your example ;-) I'm pretty sure you just have to change your "Directory /var/www/download" section to a "Location /download" in your latest example and you're OK.

Rationale is : "Directory" applies to the resulting physical directory, AFTER the rewrites have occured, whereas "Location" applies to the original URI, no matter any rewrites have occured to find the physical file.

As mod_rewrite is a huge hack that applies at various times, the effect of your code is not very obvious.

What I have in my workjing setup is :

<Location /contents/>
    Header set Content-Disposition "attachment"
</Location>
...
RewriteRule ^.*(/e-docs/.*)$   $1

So URLs like /contents/myimage.jpg AND /contents/e-docs/myimage.jpg both get the Content-Disposition header, even though /contents/e-docs/myimage.jpg is actually the /e-docs/myimage.jpg file, as the rewrite says.

Avoiding PHP for this have the added benefit that you can serve these images and potentially huge video files (as in my case) with a lightweight static Apache server, not a memory-hog PHP back-end process.

Nicolas Huillard
Great approach, thanks for adding this. I'd love to do this without PHP, especially since it does seem like a problem that should be entirely solvable with Apache.
Alex JL