Downloading files

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
therat
Forum Commoner
Posts: 62
Joined: Wed Oct 01, 2003 2:44 pm
Location: London

Downloading files

Post 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?
User avatar
hanji
Forum Commoner
Posts: 46
Joined: Fri Apr 29, 2005 3:23 pm

Post 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
therat
Forum Commoner
Posts: 62
Joined: Wed Oct 01, 2003 2:44 pm
Location: London

Post by therat »

Thanks, i'll try those later and let you know.
therat
Forum Commoner
Posts: 62
Joined: Wed Oct 01, 2003 2:44 pm
Location: London

Post 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?
User avatar
hanji
Forum Commoner
Posts: 46
Joined: Fri Apr 29, 2005 3:23 pm

Post 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
therat
Forum Commoner
Posts: 62
Joined: Wed Oct 01, 2003 2:44 pm
Location: London

Post by therat »

Thanks, i'll give it a go
Post Reply