Page 1 of 1
Downloading a file without disclosing location
Posted: Mon Jan 09, 2006 4:49 pm
by jwalsh
Hi,
I'm trying to download a file without the user knowing the existing location. But this code is actually downloading a blank file called "..-products-secretfiles-".
Code: Select all
$Download = new Download;
$Download->GetById($fileid);
$file = '../products/secretfiles/' . $Download->filename;
$type = filetype($file);
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$file");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
readfile($file);
Any ideas??
Posted: Mon Jan 09, 2006 4:59 pm
by timvw
What are you really trying to do? Because i would expect my (and others') to actually ask where to download a file (and which name to give it).
Posted: Mon Jan 09, 2006 5:08 pm
by jwalsh
The users are downloading a file they have purchased. I don't want a leak to the actual url so they can share it.
The download is now working ok... but I can't figure out how to rename the file. Right now it downloads as "products-secretfiles-filename.zip" when I only want it to say "filename.zip".
Thanks,
Josh
Code: Select all
// MAKE SURE YOU'RE ALLOWED TO DOWNLOAD FILE
if (in_array($fileid, $myfiles)) {
// load content into var
$Download = new Download;
$Download->GetById($fileid);
$file = "../products/secretfiles/" . $Download->filename;
$type = filetype($file);
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$file");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
readfile($file);
} else {
echo "DOWNLOAD NOT ALLOWED";
}
Posted: Mon Jan 09, 2006 5:11 pm
by foobar
Generate a random URL that expires after a certain amount of time.
You're best bet is probably to have a virtual "downloads" directory, and everything beyond that is passed to your file-serving script, which then determines if that URL is valid or if it has expired.
Posted: Mon Jan 09, 2006 5:52 pm
by jwalsh
I'm not sure I follow. The code I attached above won't work? It should be secure since it runs authentication before prompting the download.
Now that I check, it's not actually downloading the file, simply creating a blank file with that filename... so I'm lost. Can someone point me to an example, documentation, or something to get me started?
Thanks again.
Posted: Tue Jan 10, 2006 6:11 am
by timvw
Actually, jwalsh' strategy seems better (thats how we do it overhere too). At first sight it seems all ok (so you might want to check if the $file really exists (eg: print realpath($file)) and test if it's readable...
Posted: Tue Jan 10, 2006 6:53 am
by shiznatix
how exactally would one go about making a random url that expires after some time?
Posted: Tue Jan 10, 2006 7:34 am
by Jenk
use of mod-rewrite.
actual url will be something like:
Code: Select all
/downloads/file.php?fid=xqz1wesfh3
whilst the modrewrite constructs a url like:
a DB table contains a date stamp and the fid, if the file is older than so many minutes/hours, it is invalid and the file.php script redirects to 401/404. You can also include the users login credentials on the table for further security.
Posted: Tue Jan 10, 2006 9:18 am
by feyd
mod_rewrite isn't needed, but it makes it "nicer."
Generally, an entry into the database will be created when they select to download the file. This entry will map the random garble to the actual file and when it's supposed to expire. The entry could track how many times it's been downloaded (that particular entry) as well, to help you log whether you want to shorten the lifetime to help curb <span style='color:blue' title='I'm naughty, are you naughty?'>smurf</span> .. requesting domain filtering can also help, but create false positives..
Posted: Tue Jan 10, 2006 11:52 am
by jwalsh
Everyone,
I've played with this overnight, and still no luck. The print realpath($file) works fine, and shows the correct location.
It still creates a blank file with the name ..-products-secretfiles-filename.zip. 0kb.
[EDIT: I forgot to uncomment readfile()... LOL. The download does download the file now.... but how can I change the filename, so it doesn't show the "products-secretfiles"]
Here's the full code for the download page....
Code: Select all
<?
require_once("config.php");
AllowedHere(array(1,9));
$fileid = $_REQUEST['id'];
$myfiles = array();
// COLLECT ARRAY OF USERS FILES
$DB = new DB;
$DB->query("SELECT * FROM orders WHERE status = 3 AND memberid = {$ME->id}");
foreach ($DB->all_rows AS $completeorders) {
$DB2 = new DB;
$DB2->query("SELECT * FROM orderitems WHERE `order` = '{$completeorders['id']}'");
$myfiles[] = $DB2->row['fileid'];
}
// MAKE SURE YOU'RE ALLOWED TO DOWNLOAD FILE
if (in_array($fileid, $myfiles)) {
// load content into var
$Download = new Download;
$Download->GetById($fileid);
$file = "../products/secretfiles/" . $Download->filename;
$type = filetype($file);
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$file");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
readfile($file);
} else {
echo "DOWNLOAD NOT ALLOWED";
}
?>
Posted: Tue Jan 10, 2006 12:01 pm
by jwalsh
As always, I rack my brain all night for a solution, and as soon as I post here I find it. Here it is for anyone curious.
What I did not understand is that...
Code: Select all
header("Content-Disposition: attachment;filename=$file2");
... determines the download filename, not the source of the download. Thus I needed a second variable with the filename without the location, and used readfile() to generate the real location.
Here's a full code drop.
Code: Select all
<?
require_once("config.php");
AllowedHere(array(1,9));
$fileid = $_REQUEST['id'];
$myfiles = array();
// COLLECT ARRAY OF USERS FILES
$DB = new DB;
$DB->query("SELECT * FROM orders WHERE status = 3 AND memberid = {$ME->id}");
foreach ($DB->all_rows AS $completeorders) {
$DB2 = new DB;
$DB2->query("SELECT * FROM orderitems WHERE `order` = '{$completeorders['id']}'");
$myfiles[] = $DB2->row['fileid'];
}
// MAKE SURE YOU'RE ALLOWED TO DOWNLOAD FILE
if (in_array($fileid, $myfiles)) {
// load content into var
$Download = new Download;
$Download->GetById($fileid);
$file = "../products/secretfiles/" . $Download->filename;
$type = filetype($file);
$file2 = $Download->filename;
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$file2");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
readfile($file);
} else {
echo "DOWNLOAD NOT ALLOWED";
}
?>
Posted: Tue Jan 10, 2006 1:55 pm
by timvw
I must have looked over it... but my
download version had it already

Posted: Tue Jan 10, 2006 1:57 pm
by jwalsh
LOL... Oh well

It got done!