关于stream:在PHP中创建大型zip存档

Create big zip archive in PHP

在当前的一个PHP项目中,我需要将一堆PDF文件打包到某种归档文件中,这样用户就可以一起下载它们了。因为Zip是最常见的,甚至是最基本的非IT Windows用户都知道的,所以我要找一个Zip存档。

我的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$invoices = getRequestedInvoices(); // load all requested invoices, this function is just for demonstration

// Create a temporary zip archive
$filename = tempnam("tmp","zip");
$zip = new \ZipArchive();
$zip->open($filename, \ZipArchive::OVERWRITE);

foreach($invoices as $invoice)
{
    // create the pdf file and add it to the archive
    $pdf = new InvoicePdf($invoice); // this is derived from \ZendPdf\PdfDocument
    $zip->addFromString($pdf->getFilename(), $pdf->render()); // for clarification: the getFilename method creates a filename for the PDF based on the invoice's id
}

$zip->close();

header('Content-Type: application/zip');
header('Content-Length: ' . filesize($filename));
header('Content-Disposition: attachment; filename="invoices.zip"');
readfile($filename);
unlink($filename);
exit;

如果服务器有足够的内存,这个脚本就可以正常工作。不幸的是,我们的生产系统非常有限,所以脚本只能与几个PDF文件一起工作,但大多数时间它会耗尽内存并中止。在foreach循环的末尾添加unlink($pdf)没有帮助,所以我猜zipArchive对象正在耗尽内存。

我正试图向项目中添加尽可能少的依赖项,所以我希望能够用phps(php 5.4)自己的函数或zend framework 2中的函数来解决这个问题。我在寻找直接流式传输归档文件的方法(zip://stream包装器起初看起来不错,但它是只读的),但对于zip归档文件来说,这似乎是不可能的。

有人有主意吗?可能是一种不同但又广为人知的允许流式传输的归档类型?压缩不是必须的


我必须找到一个快速解决这个问题的方法,所以尽管试图避免它,我还是不得不使用一个外部依赖。

我在phpzip项目(https://github.com/grant/phpzip)中找到了zipstream类,它可以很好地完成工作。

1
2
3
4
5
6
7
8
9
10
$zip = new \ZipStream("invoices.zip");

foreach($invoices as $invoice)
{
    $pdf = new InvoicePdf($invoice);
    $zip->addFile($pdf->render(), $pdf->getFilename());
}

$zip->finalize();
exit;