Php fread的下载速度比readfile慢得多

Php fread的下载速度比readfile慢得多,php,download,fopen,readfile,Php,Download,Fopen,Readfile,我通过一个PHP脚本从URL向我的用户提供下载服务。使用readfile()时,我获得了连接所能支持的最大下载速度(约2.5MB/s),但使用fopen、fread、fclose路由时,下载速度非常非常慢(约1-2KB/s) 这是我的密码: header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: atta

我通过一个PHP脚本从URL向我的用户提供下载服务。使用
readfile()
时,我获得了连接所能支持的最大下载速度(约2.5MB/s),但使用
fopen、fread、fclose
路由时,下载速度非常非常慢(约1-2KB/s)

这是我的密码:

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);
}
readfile代码就是
readfile($link)

我不能只使用
readfile()
函数,因为有两个原因,一个是我想限制用户的下载速度(我可以通过
fread
只读取这么多数据来实现这一点),另外我还想跟踪用户的下载量(我可以通过
readfile()
来实现,但不计算部分下载)

有人知道为什么会发生这种情况,或者我如何修复它吗?据我所知,
readfile()
只是
fopen、fread和fclose的包装,所以我不知道出了什么问题

编辑:最终选择了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;
}
使用及

您还可以尝试将文件读取长度变大,并加入usleep()以降低执行速度。 无论如何,对于最新版本的PHP,流函数似乎比fread更受推荐。 您可能还希望在fread()或stream_get_contents()前面加一个@,以抑制任何错误,至少在生产中是这样。如果没有它,再加上一点小麻烦,你就会有一个损坏的文件。

它可能在PHP或Apache中的某个地方进行缓冲(甚至可能是速率限制)。尝试更改:

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

(前缀
@
是因为他们可能会抱怨缓冲区空。)


正如淡水先生所说,您应该对您的
fread
呼叫进行错误检查,因此我在上面添加了一些基本内容。

原因是2014年。操作系统获取4096字节数据的速度比其他操作系统快。但若你们写2014,那个么操作系统会尝试从文件中读取一个字节的数据来计算它。这就是为什么要花这么长时间。将2014更改为4096

您真的需要输出缓冲吗?尝试
ob_end_flush()我不确定,我从其他地方得到了这段代码,它有输出缓冲。我应该把
ob_end_flush()放在哪里?在开始编写之前将其放在任何地方。如果增加fread的长度参数(示例中的2014),会发生什么情况?顺便问一下,文件的大小是多少?没什么,长度参数已经超过了相应的下载速度。文件大小约为100mb。这是一个猜测,还是应该更快一些?我希望看到一些替代方案的基准。这需要一些解释。如果stream\u get\u contents的速度更快,那么为什么fread不做stream\u get\u contents所做的事情呢?这是基于知道stream\u get\u contents()不会超时,并根据服务器的条件处理它所知道的事情。我只是用一个没有读取长度的大文件尝试了每种方法,fread超时导致了一个内部服务器错误,流的内容也正常工作。但在2014年的读取长度下,两者的平均执行时间大致相同。我希望我的评论能和其他人同步,但我并没有“添加评论”按钮。您的回复是第一次出现,但仅针对此块。这是问题的解决方案,但我最终使用了不同的方法使用cURL和
CURLOPT_WRITEFUNCTION
,我将在帖子中编辑它。cURL允许我轻松地将HTTP范围头添加到请求中。谢谢!:)您还可以在启动stream_context_create()时添加HTTP读取器。查看文档。它应该以同样的方式工作。不管怎样,我只是想提一下。
while(!feof($file)) {
   echo fread($file, 2014);
}
while(!feof($file)) {
   $s=fread($file, 2014);
   if($s===false)break;  //Crude
   echo $s;
   @ob_flush();@flush();
}