Page 1 of 1

Downloading files

Posted: Sun May 01, 2005 4:35 pm
by therat
I have modified some code I found on here but am having a problem with it. The file is used to download a file when a link is clicked. I can get the file to start downloading with the correct name & type but not all the file downloads.
I have a column in the DB for the file size, for example 1631613 = 1.6mb. The original script used

Code: Select all

filesize($file);
which I assume is the problem. The whole script is now

Code: Select all

<?php
error_reporting(E_ALL);

include('includes/head.php');

if (isset($_GET['id']) && ctype_digit($_GET['id'])){
   $id = $_GET['id']; 
}

$conf = config();

$sql = "SELECT * FROM skinz_images WHERE subs_id = ".$id." AND status='1'";
$res = $database->DB_Query($sql, $skinz) or die(mysql_error());
$row = mysql_fetch_assoc($res);

$file =  $conf['subs_image_path'] . $row['subs_thumb_file'];

$size = $row['subs_zsize'];
$content = $row['subs_mime'];
$name = $row['subs_download_file'];

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-length: $size");
header("Content-type: $content");
header("Content-Disposition: attachment; filename=$name");
readfile($file);

echo $size;
?>
Do I need to put the filesize part back in somehow? Also, is this a secure method of doing this, can this be made more secure?

Posted: Sun May 01, 2005 4:59 pm
by hanji
Can you clarify.. is it a partial download? Is it close to the required size? I'm encountering a similar problem (only 3 bytes off on zip files). I would filesize() the incomplete download. .and see how much your are off.

You could try the filesize again...just for a test..

Code: Select all

header("Content-length: ".filesize('/path/to/your/file'));
Also, is this a secure method of doing this, can this be made more secure?
You have this...

Code: Select all

if (isset($_GET['id']) && ctype_digit($_GET['id'])){
   $id = $_GET['id']; 
}
This is cool.. I like the ctype_digit check. I personally don't like to use integers passed in the query. You're open to 'data-mining'.. meaning.. can I try id=6 or 7 or 8 or 9. I don't think this is a 'big' issue with this application. On another note.. you're setting yourself up for for undefined variable if the condition is false. Meaning if I pass id=foo, it'll fail the condition and $id won't be set. I would do the following...

Code: Select all

if (isset($_GET['id']) && ctype_digit($_GET['id'])){
   $id = $_GET['id']; 
}else{
header("Location:http://www.yourdomain.com/webroot/");
exit();
}

// or

if (isset($_GET['id']) && ctype_digit($_GET['id'])){
   $id = $_GET['id']; 
}else{
echo "Error";exit();
}

// or

$id = -1;
if (isset($_GET['id']) && ctype_digit($_GET['id'])){
   $id = $_GET['id']; 
}
Let me know what you find out on the file size diff.. or filesize() in the header fixes your problem.

hanji

Posted: Mon May 02, 2005 8:26 am
by therat
Thanks, i'll try those later and let you know.

Posted: Mon May 02, 2005 3:40 pm
by therat
It is only downloading a smal part of the file. I am using a test file that is 567kb, the download only does 25kb and then stops. Moving the filesize() into the header statement makes no difference.
When I do this

Code: Select all

$size = filesize($row['subs_zsize']);
the file will download but without saying how large the file is in the dialog box. When the download completes the file will not open saying it is corrupt. Is it because I am getting the filesize from a field in the database. Is there another way of doing this?

Posted: Mon May 02, 2005 10:18 pm
by hanji
$size = filesize($row['subs_zsize']);
Hmm.. that shouldn't work since what is coming out of the DB as an int value, and you're running a filesize() call around that. filesize() takes a full path to the file you want to size.

I'm wondering if it is something with readfile(). I usually do fpassthru(). Can you try this out??

Code: Select all

<?
$FileName		= "someimage.jpg";
$FileVal		= "/full/complete/path/to/file/".$FileName;
if(!$fp	= fopen(trim($FileVal),'rb')){
	echo "Can't read file";
	exit();
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=\"".trim($FileName)."\"");
header("Content-Transfer-Encoding: binary"); 
header("Content-Length: ".filesize($FileVal)."\n"); 
@fpassthru($fp);
@fclose($fp);
?>
This works without a problem for me.
HTH
hanji

Posted: Tue May 03, 2005 2:38 pm
by therat
Thanks, i'll give it a go