Page 1 of 1

Best method for hiding URL/location of downloaded article

Posted: Mon Oct 30, 2006 4:24 am
by intergroove
I wish to offer downloads Files, MP3s, documents, etc.

I'd like these to be on a token basis, either payed for or by invite.

I need to make the files secure by hiding their location.

What are the competing methods to do this? and what are the pros and cons of each?

My site is PHP/MySQL based & I currently have my download files on a separate server to my site.

Thanks in advance...

Posted: Mon Oct 30, 2006 6:04 am
by Chris Corbyn
I don't think there are too many options.

PHP can just stream the data itself from a file stored outside of the webroot; or you can use a Java applet such as Anti-Leech. Either way, the main thing is to not store the actual file inside the web root.

Posted: Mon Oct 30, 2006 6:07 am
by kettle_drum
I would just make a script that processes the download by setting the correct file type headers and then echos the content of the file to the user. This will allow you to point a user to:

download.php?file=xyz

Etc, and they wont be able to see the path to the actual file - which can be stored in a non web accessible location.

You can then take this a step further by giving each download a unique ID, which references to a file path in a database and you can then remove this record upon successful download so people cant re-use the link to download the file. Since its also going through a php script you can check to make sure the user has a cookie set or was referred from a certain location etc.

The only other way I can think of doing this is to individually copy the requested file to a random location each time its requested and then remove once its download - but unless you download the file through a php/asp/ruby script you cant check for user privileges etc - and of course this would end up wasting a huge amount of disc space.

Posted: Mon Oct 30, 2006 7:20 am
by aaronhall
Ditto kettle_drum. Check out file_get_contents and header.

Posted: Mon Oct 30, 2006 10:08 am
by intergroove
feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


Thanks for the tips guys.

This is what I have come up with. I've had to force-download the MP3. 

Obviously: $media = media type , $file = filename  

I guess I could grab the media type from the filename, but this isn't important at this stage.

Code: Select all

<?
define("_ROOT_", $_SERVER['DOCUMENT_ROOT']);
$media = trim(htmlspecialchars($_GET["media"]));
switch ($media) {
    case "pdf": $ctype="application/pdf"; define("_FOLDER_","/docs/"); define("DOWNLOAD", true); break;
    case "zip": $ctype="application/zip"; define("_FOLDER_","/zips/"); define("DOWNLOAD", true); break;
    case "doc": $ctype="application/msword"; define("_FOLDER_","/docs/"); define("DOWNLOAD", true); break;
    case "xls": $ctype="application/vnd.ms-excel"; define("_FOLDER_","/docs/"); define("DOWNLOAD", true); break;
    case "ppt": $ctype="application/vnd.ms-powerpoint"; define("_FOLDER_","/docs/"); define("DOWNLOAD", true); break;
    case "gif": $ctype="image/gif"; define("_FOLDER_","/images/"); define("DOWNLOAD", true); break;
    case "png": $ctype="image/png"; define("_FOLDER_","/images/"); define("DOWNLOAD", true); break;
    case "jpe":
    case "jpg":
    case "jpeg": $ctype="image/jpg"; define("_FOLDER_","/images/"); define("DOWNLOAD", true); break;
    case "wmv": $ctype = "video/x-ms-wmv"; define("_FOLDER_","/media/"); define("DOWNLOAD", true); break;
    case "mp3": $ctype = "application/force-download"; define("_FOLDER_","/media/"); define("DOWNLOAD", true); break;
    case "mpg": $ctype = "video/mpeg"; define("_FOLDER_","/media/"); define("DOWNLOAD", true); break;
    default: ?><p style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; font-weight: bold; color: #ff0000; ">Invaid file type or filename.</p><? break;
}
$file = _ROOT_._FOLDER_.basename($_GET['file']);
if (file_exists($file) && defined("DOWNLOAD")) {
    list($filename, $ext) = explode(".", basename($file));
    if($media == $ext) {
        header("Pragma: public"); 
        header("Expires: 0"); 
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 
        header("Cache-Control: private",false); 
        header("Content-Type: $ctype"); 
        header("Content-Disposition: attachment; filename=\"".basename($file)."\";"); 
        header("Content-Transfer-Encoding: binary"); 
        header("Content-Length: ".@filesize($file)); 
        set_time_limit(0); 
        @readfile($file) or die("File not found."); 
        exit;
    }
    else { ?><p style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; font-weight: bold; color: #ff0000; ">Invaid file type or filename.</p><? }
}
else { die("Filename '".basename($file)."' Not Found!"); }
?>
Let me know if you can spot any obvious flaws in it.

I'm going to launch this as a pop-up (I guess using a javascript launch) - are there any issues I should be aware of? or any techniques I should use?


feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]

Posted: Mon Oct 30, 2006 3:17 pm
by timvw
basic-download-script.

I would expect a decent script to understand the 'Range/partial content' header too (something like http://www.phpclasses.org/browse/file/9051.html).. Implementing the business rules and mapping between request and actual file on disk is up to you ;)