I'm serving downloads from a URL to my users through a PHP script. When using readfile()
I get the maximum download speed my connection can support (about 2.5MB/s) however when I use the fopen, fread, fclose
route the download speed is very, very slow (about 1-2KB/s).
Here's my code:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $filesize);
ob_clean();
flush();
$file = fopen($url, 'rb');
while(!feof($file)) {
echo fread($file, 2014);
}
and the readfile code is simply readfile($link);
.
I can't just use the readfile()
function because of two reasons, one is I want to restrict the users download speed (which I can do with fread
by only reading so much data) and I also want to track how much a user is downloading (I can do this with readfile()
but it doesn't count partial downloads).
Does anyone know why this might be happening or how I can fix it? As far as I know readfile()
is just a wrapper for fopen, fread and fclose
so I don't get what's going wrong.
Edit: Ended up going with cURL for this.
$curl = curl_init();
$options = array(
CURLOPT_URL => $rdLink,
CURLOPT_FAILONERROR => true,
CURLOPT_BINARYTRANSFER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_WRITEFUNCTION => 'readResponse'
);
curl_setopt_array($curl, $options);
if(!curl_exec($curl)) {
header('Location: http://whatever.com');
exit;
}
curl_close($curl);
function readResponse($ch, $data) {
$length = mb_strlen($data, '8bit');
echo $data;
return $length;
}
It might be buffering (or perhaps even rate-limiting) somewhere in PHP or Apache. Try changing:
To:
(The
@
prefix is because they might complain about empty buffers.)As mr.freshwater said, you ought to have error-checking on your
fread
call, so I've added something basic above.Use stream_context_create() and stream_get_contents()
You could also try making the file read length larger and putting in a usleep() to slow execution. The stream functions seem to be recommended over fread for the latest version of PHP anyway. You might want to also prepend an @ in front of the fread() or stream_get_contents() to suppress any errors, at least in production. Without it, and a little mishap, and you have a corrupted file.
The reason is 2014. OS gets 4096 byte data portion very fast then others. But if you write 2014, then OS tries to read data from file by one byte to calculate it. That's why it takes so long time. Change 2014 to 4096