7

I stumbled upon strange way to protect files.

Basicly there is empty download.php file in protected folder and two files that cause file to be downloaded (from the same folder): .htpwd where password is stored and .htaccess:

RewriteEngine On
##RewriteBase /
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example.com [NC]
RewriteRule \.(.*)$ - [NC,F,L]

RewriteCond %{QUERY_STRING} ^filename=(.*)$
RewriteRule ^download\.php$ %1
RewriteRule (.*) - [E=file:$1]
Header set Content-type "octet-stream"
Header set Content-disposition "attachment; filename=%{file}e" env=file

##AuthName "Restricted Access" 
##AuthType Basic
##AuthUserFile /local/home/example/example.com/downloads/.htpwd
##AuthGroupFile /dev/null 
##require valid-user

Example of download link:
http://www.example.com/downloads/download.php?filename=dog%20cat%20cow.zip

If filename is dog-cat-cow.zip - all works. Problem starts when filename is: "dog cat cow.zip" then file will be downloaded but its file name after download will be "dog" instead of "dog cat cow.zip". So problem is people get file without even extension and have no idea what to do with it.

How this can be solved considering i simply cannot rename those files and remove spaces? I'm not expert on how to read .htaccess and no phrase that I could think of to search gives any similar problem resolution. Any ideas?

MrWhite
  • 43,179
  • 8
  • 60
  • 84
Greg Viv
  • 817
  • 1
  • 8
  • 22
  • 4
    i recommend you do something like this `Header set Content-disposition "attachment; filename='%{file}e'" env=file`, filename in quotes – manjeet Aug 05 '15 at 15:09
  • 1
    As @anonymous says, since the filename has spaces, you'll need quote delimiters. However, what is that extra `e` for? – MrWhite Aug 05 '15 at 15:11
  • "but its file name after download" - you can get the browser to always prompt for the location of the download (recommended) - at that stage the user can correct the filename. – MrWhite Aug 05 '15 at 15:12
  • Trick from the 1st comment did the job but only when I tried in new browser. Any good way to force clearing cache for this htaccess? – Greg Viv Aug 05 '15 at 15:32
  • The cache is for that particular request ie. `/downloads/download.php?filename=dog%20cat%20cow.zip`, not "for this .htaccess" - will many users that have already downloaded that file want to download it again? The problem with this is that if the user has already cached it then there's not much you can do about it. You can only minimise the cache time from now going forward, for new requests. But then you will never benefit from the client-side cache for these download requests. – MrWhite Aug 05 '15 at 17:12

1 Answers1

1

As mentioned in comments, maybe try:

RewriteEngine On
##RewriteBase /
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example.com [NC]
RewriteRule \.(.*)$ - [NC,F,L]

RewriteCond %{QUERY_STRING} ^filename=(.*)$
RewriteRule ^download\.php$ %1
RewriteRule (.*) - [E=file:$1]
Header set Content-type "octet-stream"
Header set Content-disposition "attachment; filename='%{file}'" env=file

##AuthName "Restricted Access" 
##AuthType Basic
##AuthUserFile /local/home/example/example.com/downloads/.htpwd
##AuthGroupFile /dev/null 
##require valid-user

Alternately, why not set the Content Type and Disposition within your download.php file itself?

$fileStorageDirectory = '/the/folder/the/downloadable/files/are/in/';

// Check for Parameter
if( !isset( $_GET['filename'] ) || $_GET['filename']=='' ){
  header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found', true, 404);
  die('No File Specified');
}

$fileName = trim( $_GET['filename'] );
$fileRequested = $fileStorageDirectory.$fileName;
// Check File Exists
if( !file_exists( $fileRequested ) ){
  header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found', true, 404);
  die('File Not Found');
}
// Check File is Readable
if( !is_readable( $fileRequested ) ){
  header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found', true, 404);
  die('File Not Accessible');
}
// Send the File
header( 'Content-Type: application/octet-stream' );
header( 'Content-Disposition: attachment; filename="'.fileName.'"' );
readfile( $fileRequested );
exit;
Luke Stevenson
  • 10,357
  • 2
  • 26
  • 41