用PHP + Apache高速生成ZIP文件?

引用一些着名的词语 :

“程序员经常为了工作的复杂性和创造性而倾向于一种可以理解但却是灾难性的倾向。 不允许devise大于程序的任何东西,他们的反应是让程序复杂到足以挑战他们的专业技能。“

在解决一些普通的问题的同时,我提出了这个想法,我不太清楚如何解决。 我知道我不会执行这个,但我很好奇最好的解决scheme是什么。 🙂


假设你有这个JPG文件和一些奇怪的SWF文件这个大集合。 与“大”我的意思是“几千”。 每个JPG文件大约200KB,SWF文件大小可以达到几MB。 每天都有一些新的JPG文件。 所有东西的总大小约为1GB,并且正在缓慢而稳定地增长。 文件很less更改或删除。

用户可以在网页上单独查看每个文件。 然而,也有希望让他们一下子下载一大堆。 这些文件有一些元数据附加到他们(date,类别等),用户可以通过过滤集合。

最终的实现将允许用户指定一些过滤标准,然后将相应的文件作为一个ZIP文件下载。

由于标准的数量足够大,所以我不能预先生成所有可能的ZIP文件,并且必须立即执行。 另一个问题是,下载可能会相当大,对于连接速度慢的用户来说,很可能需要一个小时或更长的时间。 因此支持“简历”是必须的。

然而在光明的一面,ZIP不需要压缩任何东西 – 无论如何,文件大多是JPEG。 因此整个过程不应该比简单的文件下载更占用CPU资源。

那么我已经确定的问题是:

  • PHP的脚本执行超时。 虽然它可以通过脚本本身来改变,但是完全删除它是否没有问题?
  • 使用resume选项,可能会针对不同的HTTP请求更改filter结果。 这可以通过按时间顺序对结果进行sorting来减轻,因为集合只是越来越大。 然后,请求URL将包含最初创build的date,而脚本不会考虑比这更年轻的文件。 这足够吗?
  • 通过PHP传递大量的文件数据本身不是一个性能问题?

你将如何执行这个? PHP完全可以完成任务吗?


添加:

到目前为止,两个人已经build议将所需的ZIP文件存储在一个临时文件夹中,并像通常的文件一样从那里提供它们。 虽然这确实是一个明显的解决scheme,但是有几个实际的考虑因素使得这是不可行的。

ZIP文件通常会相当大,从几十兆字节到百万兆字节。 用户请求“全部”也是完全正常的,这意味着ZIP文件将超过千兆字节。 也有许多可能的滤波器组合,其中许多可能被用户select。

因此,ZIP文件生成会非常缓慢(由于数据量和磁盘速度),并且将包含整个集合很多次。 我没有看到这个解决scheme如何工作,没有一些昂贵的SCSI RAIDarrays。

这可能是你需要的: http : //pablotron.org/software/zipstream-php/

这个库允许你建立一个动态的流式压缩文件而不用交换到磁盘。

使用例如PhpConcept库Zip库。

恢复必须由您的网络服务器支持,除非您不直接访问zipfiles。 如果你有一个PHP脚本作为中介,然后注意发送正确的标题,以支持恢复。

创建文件的脚本不应该超时,只要确保用户不能一次选择数千个文件。 并保留一些东西,以删除“旧zipfiles”,并注意到一些恶意用户不会通过请求许多不同的文件集合用完你的磁盘空间。

你将不得不存储生成的zip文件,如果你想他们能够恢复下载。

基本上,你生成的zip文件,并用可重复的文件名(可能搜索过滤器的哈希)在/ tmp目录中查找它。 然后,将正确的标题发送给用户,并向用户回显file_get_contents。

为了支持恢复,你需要检查$ _SERVER ['HTTP_RANGE']的值,这里的格式是详细的,一旦你解析,你需要运行这样的东西。

$size = filesize($zip_file); if(isset($_SERVER['HTTP_RANGE'])) { //parse http_range $range = explode( '-', $seek_range); $new_length = $range[1] - $range[0] header("HTTP/1.1 206 Partial Content"); header("Content-Length: $new_length"); header("Content-Range: bytes {$range[0]}-$range[1]"); echo file_get_contents($zip_file, FILE_BINARY, null, $range[0], $new_length); } else { header("Content-Range: bytes 0-$size"); header("Content-Length: ".$size); echo file_get_contents($zip_file); } 

这是非常粗略的代码,你可能需要玩弄头文件和HTTP_RANGE变量的内容。 如果你愿意,你可以使用fopen和fwrite,而不是file_get的内容。

现在你的问题

  • PHP的脚本执行超时。 虽然它可以通过脚本本身来改变,但将它完全删除是没有问题的?

你可以删除它,但如果你想要的话,但是如果有东西变成梨形,而且你的代码被卡在一个无限循环中会导致有趣的问题,如果这个无限循环在某处记录和错误,而你没有注意到,直到一个相当脾气暴躁sys-admin奇怪为什么他们的服务器用完了硬盘空间;)

  • 使用resume选项,可能会针对不同的HTTP请求更改过滤器结果。 这可以通过按时间顺序对结果进行排序来减轻,因为集合只是越来越大。 然后,请求URL将包含最初创建的日期,而脚本不会考虑比这更年轻的文件。 这足够吗?

缓存文件到硬盘,意味着你不会有这个问题。

  • 通过PHP传递大量的文件数据本身不是一个性能问题?

是的,它不会像从网络服务器的常规下载一样快。 但它不应该太慢。

我有一个下载页面,并做了一个类似于您的想法的zip类。 我的下载是非常大的文件,无法正确压缩zip文件。

我和你有类似的想法。 放弃压缩的方法是非常好的,你甚至不需要更少的cpu资源,因为你不需要触摸输入文件并且可以传递它,所以你可以节省内存,你也可以计算一切,比如压缩文件头而且文件结尾很容易,你可以跳到每一个位置,从这一点产生实现简历。

我更进一步,我从所有的输入文件crc生成一个校验和,并将其用作生成的文件的电子标签,以支持缓存,并作为文件名的一部分。 如果您已经下载了生成的zip文件,浏览器将从本地缓存中取代服务器。 您也可以调整下载速率(例如300KB / s)。 一个可以做邮编评论。 您可以选择哪些文件可以添加,哪些不可以(例如thumbs.db)。

但是,你无法用zip格式完全克服这个问题。 那就是crc值的一代。 即使使用散列文件来克服内存问题,或者使用散列更新来递增地生成crc,它也会占用太多的CPU资源。 一个人不多,但不推荐专业使用。 我解决了这个额外的crc值表,我用一个额外的脚本生成。 我将这个crc值每个参数添加到zip类。 有了这个,班级是超快的。 就像你提到的那样,像一个普通的下载脚本。

我的zip类正在进行中,您可以在这里看看: http : //www.ranma.tv/zip-class.txt

我希望我可以帮助那个:)

但是我会停止这个方法,我会把我的课程重新编译成tar类。 用tar我不需要从文件生成crc值,tar只需要一些校验和的标题,这一切。 而且我不需要额外的mysql表格了。 如果你不需要为它创建一个额外的crc表,我认为它使得这个类更容易使用。 这并不难,因为压缩文件结构更容易。

PHP的脚本执行超时。 虽然它可以通过脚本本身来改变,但将它完全删除是没有问题的?

如果您的脚本是安全的,并在用户中止时关闭,则可以将其彻底删除。 但是,如果你只是更新你通过的每一个文件的超时时间,这将是更安全的:)

使用resume选项,可能会针对不同的HTTP请求更改过滤器结果。 这可以通过按时间顺序对结果进行排序来减轻,因为集合只是越来越大。 然后,请求URL将包含最初创建的日期,而脚本不会考虑比这更年轻的文件。 这足够吗?

是的,这将工作。 我已经从输入文件crc的生成校验和。 我用这个作为电子标签,并作为zip文件的一部分。 如果更改了某些内容,用户将无法恢复生成的zip文件,因为电子标签和文件名与内容一起更改。

通过PHP传递大量的文件数据本身不是一个性能问题?

不,如果你只通过它不会使用更多,然后定期下载。 也许0.01%我不知道,它不是很多:)我假设,因为PHP不做太多的数据:)

您可以使用ZipStreamPHPZip ,它将随时将压缩文件发送到浏览器,并以块分割,而不是将整个内容加载到PHP中,然后发送zip文件。

这两个库都是很好用的代码段。 一些细节:

  • ZipStream只在内存中“工作”,但如果需要的话,不能轻易移植到PHP 4(使用hash_file() )
  • PHPZip在磁盘上写入临时文件(消耗尽可能多的磁盘空间作为在zip中添加的最大文件),但是如果需要,可以很容易地适应PHP 4。