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;
}
Use stream_context_create() and stream_get_contents()
$context = stream_context_create();
$file = fopen($url, 'rb', FALSE, $context);
while(!feof($file))
{
//usleep(1000000);
echo stream_get_contents($file, 2014);
}
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.