Henry Ing-Simmons
Henry Ing-Simmons

Reputation: 1501

mod_rewrite to download - makes suspicous looking file

I decided to try and use mod_rewrite to hide the location of a file that a user can download.

So they click on a link that's directed to "/download/some_file/" and they instead get "/downloads/some_file.zip"

Implemented like this:

RewriteRule ^download/([^/\.]+)/?$ downloads/$1.zip [L]

This works except they when the download progress appears I'm getting a file "download" with no extension which looks suspicious and the user might not be aware they are supposed to unzip it. Is there a way of doing this so it looks like an actual file? Or is there a better a way I should be doing this?

To provide some context/reason for hiding the location of the file. This is for a band where the music can be downloaded for free provided the user signs up for the mailing list.

Also not I need to do this within .htaccess

Upvotes: 0

Views: 1266

Answers (2)

Henry Ing-Simmons
Henry Ing-Simmons

Reputation: 1501

Ok so I believe that I'm restricted as to what headers I can set using .htaccess

So I have instead solved this using php.

I initially copied a download php script found here: How to rewrite and set headers at the same time in Apache

However my file size was too big and so this was not working properly.

After a bit of googling I came across this: http://teddy.fr/blog/how-serve-big-files-through-php

So my complete solution is as follows...

First send requests to download script:

RewriteRule ^download/([^/\.]+)/?$ downloads/download.php?download=$1 [L]

Then get full filename, set headers, and serve it chunk by chunk:

<?php
if ($_GET['download']){
  $file = $_SERVER['DOCUMENT_ROOT'].'media/downloads/' . $_GET['download'] . '.zip';
}

define('CHUNK_SIZE', 1024*1024); // Size (in bytes) of tiles chunk

// Read a file and display its content chunk by chunk
function readfile_chunked($filename, $retbytes = TRUE) {
    $buffer = '';
    $cnt =0;
    // $handle = fopen($filename, 'rb');
    $handle = fopen($filename, 'rb');
    if ($handle === false) {
      return false;
    }

    while (!feof($handle)) {
        $buffer = fread($handle, CHUNK_SIZE);
        echo $buffer;
        ob_flush();
        flush();
        if ($retbytes) {
            $cnt += strlen($buffer);
        }   
    }
    $status = fclose($handle);
    if ($retbytes && $status) {
        return $cnt; // return num. bytes delivered like readfile() does.
    }
    return $status;
}

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

readfile_chunked($file); 
?>

Upvotes: 0

Stefan
Stefan

Reputation: 114178

You can set the filename by sending the Content-disposition header:

https://serverfault.com/questions/101948/how-to-send-content-disposition-headers-in-apache-for-files

Upvotes: 1

Related Questions