在PHP中可靠地下载大文件

Erw*_*ing 24 php download

我在服务器上有一个PHP脚本将文件发送给配方:它们获得一个唯一的链接,然后他们可以下载大文件.有时传输出现问题,文件已损坏或永不完成.我想知道是否有更好的方法来发送大文件

码:

$f = fopen(DOWNLOAD_DIR.$database[$_REQUEST['fid']]['filePath'], 'r');
while(!feof($f)){
    print fgets($f, 1024);
}
fclose($f);
Run Code Online (Sandbox Code Playgroud)

我见过的功能如

http_send_file
http_send_data
Run Code Online (Sandbox Code Playgroud)

但我不确定他们是否会奏效.

解决这个问题的最佳方法是什么?

问候
erwing

gar*_*row 11

如果您要发送真正大的文件并担心它会产生的影响,您可以使用x-sendfile头.

从SOQ 使用-xsendfile-with-apache-php,一个howto blog.adaniels.nl:how-i-php-x-sendfile /

  • 这里有一个["**大文件下载**"PHP脚本](http://phpsnips.com/579/PHP-download-script-for-Large-File-Downloads)可处理大约**2GB**许多文件类型,如exe,mp3,mp4,pdf等.这个脚本值得通过PHP脚本下载中小文件大小.它还描述了**X-sendfile**,用于超过5GB的真正大量文件下载.看看链接. (3认同)
  • @Ben 对此感到抱歉。'phpsnips' 网站已删除该片段。可以直接从 Github 下载:https://github.com/saleemkce/downloadable/blob/master/download.php (3认同)

小智 8

最好的解决方案是依赖lighty或apache,但如果在PHP中,我会使用PEAR的HTTP_Download(不需要重新发明轮子等),有一些不错的功能,如:

  • 基本限制机制
  • 范围(部分下载和恢复)

请参阅介绍/使用文档.


tre*_*der 8

文件分块是PHP最快/最简单的方法,如果你不能或不想使用一些更专业的像卷曲,mod-xsendfile阿帕奇或一些专门的脚本.

$filename = $filePath.$filename;

$chunksize = 5 * (1024 * 1024); //5 MB (= 5 242 880 bytes) per one chunk of file.

if(file_exists($filename))
{
    set_time_limit(300);

    $size = intval(sprintf("%u", filesize($filename)));

    header('Content-Type: application/octet-stream');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: '.$size);
    header('Content-Disposition: attachment;filename="'.basename($filename).'"');

    if($size > $chunksize)
    { 
        $handle = fopen($filename, 'rb'); 

        while (!feof($handle))
        { 
          print(@fread($handle, $chunksize));

          ob_flush();
          flush();
        } 

        fclose($handle); 
    }
    else readfile($path);

    exit;
}
else echo 'File "'.$filename.'" does not exist!';
Run Code Online (Sandbox Code Playgroud)

来自richnetapps.com/NeedBee.在200 MB文件上进行测试readfile(),即使设置了最大允许内存限制,也会死亡,这1G比下载文件大小多五倍.

顺便说一句:我也在文件上对此进行了测试>2GB,但PHP只设法先写入2GB文件,然后断开连接.与文件相关的函数(fopen,fread,fseek)使用INT,因此你最终达到了极限2GB.mod-xsendfile在这种情况下,上述解决方案(即)似乎是唯一的选择.

编辑:让自己100% ,你的文件保存在utf-8.如果省略,则下载的文件将被破坏.这是因为此解决方案用于print将文件块推送到浏览器.


And*_*art 6

我们一直在几个项目中使用它,到目前为止它工作得很好:

/**
 * Copy a file's content to php://output.
 *
 * @param string $filename
 * @return void
 */
protected function _output($filename)
{
    $filesize = filesize($filename);

    $chunksize = 4096;
    if($filesize > $chunksize)
    {
        $srcStream = fopen($filename, 'rb');
        $dstStream = fopen('php://output', 'wb');

        $offset = 0;
        while(!feof($srcStream)) {
            $offset += stream_copy_to_stream($srcStream, $dstStream, $chunksize, $offset);
        }

        fclose($dstStream);
        fclose($srcStream);   
    }
    else 
    {
        // stream_copy_to_stream behaves() strange when filesize > chunksize.
        // Seems to never hit the EOF.
        // On the other handside file_get_contents() is not scalable. 
        // Therefore we only use file_get_contents() on small files.
        echo file_get_contents($filename);
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*ant 4

对于下载文件,我能想到的最简单的方法是将文件放在临时位置,并为它们提供一个可以通过常规 HTTP 下载的唯一 URL。

作为生成这些链接的一部分,您还可以删除超过 X 小时的文件。

  • 但你从中得到的是与服务器的实际 HTTP 通信的复杂性,它所属的服务器(例如过期标头、范围下载、缓存等)。*我* 宁愿使用脚本清理一些文件,也不愿在我的应用程序中重新实现 HTTP。 (3认同)