使用PHP创建和提供压缩文件

4
我正在尝试使用以下代码从目录创建zip文件,并通过http下载向用户提供服务:
 // write the file
file_put_contents($path . "/index.html", $output);

// zip up the contents
chdir($path);
exec("zip -r {$course->name} ./");

$filename = "{$course->name}.zip";

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

readfile($filename);

我能够创建zip文件,但是通过http下载它不起作用。如果我使用ftp客户端下载创建的zip文件,那么Mac的Stuffit Expander可以很好地解压缩文件,但是如果我通过http下载它,则Mac的解压程序会创建一个无限循环。我的意思是,假设我下载的文件名为course.zip,那么解压缩该文件会得到course.zip.cpgz,然后解压缩该文件又会得到course.zip,依此类推。

有人有什么想法吗?

谢谢!


2
你的应用程序/octet-stream的MIME类型并不是错误的,但使用application/zip可能更友好。 - Tony Miller
@Tony Miller - 为什么不将那作为一个答案?可能就是问题所在。 - karim79
如何在PHP中进行“即时压缩和流式传输”:https://dev59.com/mW855IYBdhLWcg3waDiR#4357904。 - Lee
4个回答

8
我遇到了这个问题,后来发现下载的zip文件在开头插入了一个新行。
通过使用ob_clean和flush函数解决了这个问题。
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false);
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=".basename($archive_file_name));
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: ".filesize($archive_file_name));
    ob_clean();
    flush();
    echo readfile("$archive_file_name");

1

根据 karim79 的建议,我将我的评论作为答案:如果您将 MIME 类型从 application/octet-stream 更改为 application/zip,会发生什么?

此外,我看到您正在使用命令行 zip 程序,但是您没有检查 zip 的成功,并且在尝试发送文件给最终用户浏览器之前也没有检查文件是否存在。尝试强制编写文件名,手动使用 zip 来保证正确形成的 zip 文件,然后查看您的代码是否能够正确地将其传输到您的浏览器中。


1
好的,我尝试将MIME类型更改为application/zip,并且硬编码一个我知道格式正确的zip文件(在上传后在我的计算机和服务器上都成功解压缩的文件),但结果相同。 - Eric Conner

1
  1. 每次请求时重新压缩并不是个好主意。仅当ZIP文件不存在时才进行重新压缩。

  2. 如果是易失性文件或只需传输单个小文件,请尝试使用ob_start('ob_gzhandler'),它更简单、更小、更干净。该文件会以压缩方式传输,但客户端会将其保存为原始格式。

  3. 指定Content-Length标头是必要的,以允许下载器知道文件结束位置,从而允许进度控制、检测文件损坏并避免HTTP会话挂起(如果连接处于Keep-Alive模式),也许缺少此标头是问题的根源。


我现在也在指定Content-Length头,但仍然无法正常工作。我本质上只是想一次向用户提供大约15个小文件,并认为压缩是我的唯一选择。是否有其他方法可以做到这一点? - Eric Conner

0

你看到的是存档工具无法将zip文件识别为zip文件,因此尝试压缩zip归档本身。第二个操作只是解压缩第一个创建的文件,因此根本没有打开文件。这是由于zip文件损坏造成的。

可能是浏览器在下载过程中某种方式搞乱了zip文件(换行符转换?)。如上所述,请检查MIME类型并使用php header()设置正确的MIME类型(application/zip)。


好的,我尝试使用application/zip,但没有成功。浏览器下载对话框告诉我,我正在尝试下载一个"PC Zip archive",当它下载到我的机器上时,OS X显示"Kind: ZIP Archive",但是当我尝试解压缩时,它却做同样的事情。(这也是使用我之前上传之前在我的机器上工作的硬编码文件) - Eric Conner

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