简体   繁体   English

fread 的下载速度比 readfile 慢很多

[英]fread a lot slower for downloads than readfile

I'm serving downloads from a URL to my users through a PHP script.我正在通过 PHP 脚本从 URL 向我的用户提供下载。 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).使用readfile()我获得了连接可以支持的最大下载速度(大约 2.5MB/s),但是当我使用fopen, fread, fclose路由时,下载速度非常非常慢(大约 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);读取文件代码只是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).由于两个原因,我不能只使用readfile()函数,一个是我想限制用户的下载速度(我可以通过只读取这么多数据来使用fread来做到这一点),而且我还想跟踪用户的下载速度正在下载(我可以用readfile()做到这一点,但它不计算部分下载)。

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.据我所知readfile()只是fopen, fread and fclose的包装器fopen, fread and fclose所以我不明白出了什么问题。

Edit: Ended up going with cURL for this.编辑:为此最终使用了 cURL。

$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;
}

Usestream_context_create() and stream_get_contents()使用stream_context_create()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.您还可以尝试使文件读取长度更大并放入 usleep() 以减慢执行速度。 The stream functions seem to be recommended over fread for the latest version of PHP anyway.无论如何,对于最新版本的 PHP,流函数似乎比 fread 更推荐。 You might want to also prepend an @ in front of the fread() or stream_get_contents() to suppress any errors, at least in production.您可能还想在 fread() 或 stream_get_contents() 前面加上 @ 以抑制任何错误,至少在生产中是这样。 Without it, and a little mishap, and you have a corrupted file.没有它,稍有不慎,您的文件就会损坏。

It might be buffering (or perhaps even rate-limiting) somewhere in PHP or Apache.它可能在 PHP 或 Apache 中的某处进行缓冲(甚至可能是速率限制)。 Try changing:尝试改变:

while(!feof($file)) {
   echo fread($file, 2014);
}

To:到:

while(!feof($file)) {
   $s=fread($file, 2014);
   if($s===false)break;  //Crude
   echo $s;
   @ob_flush();@flush();
}

(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.正如freshwater先生所说,你应该对你的fread调用进行错误检查,所以我在上面添加了一些基本的东西。

The reason is 2014. OS gets 4096 byte data portion very fast then others.原因是 2014 年。操作系统比其他人更快地获取 4096 字节数据部分。 But if you write 2014, then OS tries to read data from file by one byte to calculate it.但是如果你写 2014,那么操作系统会尝试从文件中读取一个字节的数据来计算它。 That's why it takes so long time.这就是为什么需要这么长时间。 Change 2014 to 4096将 2014 更改为 4096

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM