将zip文件发送到浏览器 / 强制直接下载

20

可能是强制下载远程文件的任何方法?的重复问题。 - cweiske
4个回答

47
<?php
    // or however you get the path
    $yourfile = "/path/to/some_file.zip";

    $file_name = basename($yourfile);

    header("Content-Type: application/zip");
    header("Content-Disposition: attachment; filename=$file_name");
    header("Content-Length: " . filesize($yourfile));

    readfile($yourfile);
    exit;
?>

为什么我看到它作为内联内容,而不是提示我下载? - Redoman
@jj 我没有在文档开头使用这段代码! - Redoman
它在所有操作系统(特别是Windows)和浏览器中进行了测试吗? - RN Kushwaha
使用exit进行测试是不好的实践。确保您的脚本完成,但不要使用exit。它还会结束任何phpunit测试,并且没有恢复的方法... - Benjamin Eckstein

7
如果您已经将ZIP文件上传到服务器上,并且此ZIP文件可以通过HTTP或HTTPS被Apache访问,那么您应该重定向到该文件,而不是使用PHP“读取”它。
这样做会更加高效,因为您不需要使用PHP,因此不需要CPU或RAM,同时下载速度也会更快,因为没有PHP读写操作,只有直接下载。 让Apache来完成这项工作吧!
所以一个不错的函数可能是:
if($is_reachable){
    $file = $relative_path . $filename; // Or $full_http_link
    header('Location: '.$file, true, 302);
}
if(!$is_reachable){
    $file = $relative_path . $filename; // Or $absolute_path.$filename
    $size = filesize($filename); // The way to avoid corrupted ZIP
    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename=' . $filename);
    header('Content-Length: ' . $size);
    // Clean before! In order to avoid 500 error
    ob_end_clean();
    flush();
    readfile($file);
}
exit(); // Or not, depending on what you need

I hope that it will help.


ob_end_clean(); - zod
“$is_reachable” 是从哪里来的? - Andrei Surdu
1
嗨,Andrei。你想从哪里开始!这可能是你自己的测试,取决于你的代码编写方式。例如,如果你现在知道ZIP已经存在(因为你不需要生成它),并且可以通过直接链接访问(无需授权)。 总之:如果你可以使用直接链接下载ZIP,则可达;否则(需要身份验证、奇怪的链接或其他原因),你需要使用PHP“强制”下载。 - XDjuj

6
设置 content-type、content-length 和 content-disposition 头部,然后输出文件。
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Length: '.filesize($filepath) );
readfile($filepath);

设置Content-Disposition: attachment将建议浏览器下载文件而不是直接显示它。


这是否意味着对于大型下载,文件会通过 PHP 服务器传输? - Ben

2

你需要这样做,否则你的压缩文件可能会损坏:

$size = filesize($yourfile);
header("Content-Length: \".$size.\"");

所以 content-length 头需要一个真实字符串,而 filesize 返回一个整数。

3
谢谢您的评论,由于我使用了header('Content-Length: '.filesize($filepath) );,所以我在损坏的zip文件上浪费了几个小时。您的解决方案更有效。 - niko craft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接