【发布时间】:2023-03-23 04:00:02
【问题描述】:
我需要向客户提供像 file.zip (~2 GB) 这样的大文件,每个客户都有一个唯一的 URL。然后我将(使用.htaccess)重定向客户下载链接example.com/download/f6zDaq/file.zip 到类似的东西
example.com/download.php?id=f6zDaq&file=file.zip
但是由于文件很大,我不希望 PHP 处理下载(而不是让 Apache 处理它)成为我服务器的 CPU / RAM 性能问题。毕竟,要求 PHP 这样做涉及到一个新层,所以如果没有正确处理,可能会导致这样的问题。
问题:在以下解决方案中,哪些是最佳做法?(特别是在 CPU/RAM 方面)?
-
1:使用
application/download的PHP解决方案header('Content-Type: application/download'); header('Content-Disposition: attachment; filename=file.zip'); readfile("/path/to/file.zip");下载时测得的 CPU 使用率:13.6%。
-
1bis:使用
application/octet-stream的PHP 解决方案(来自this page 的示例#1)header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=file.zip'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize('file.zip')); readfile("/path/to/file.zip"); -
1ter:
application/octet-stream的 PHP 解决方案(来自 here):header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=file.zip'); header('Content-Transfer-Encoding: binary'); // additional line header('Connection: Keep-Alive'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); // additional line header('Pragma: public'); header('Content-Length: ' . filesize('file.zip')); readfile("/path/to/file.zip"); -
1quater:另一个带有
application/force-download的PHP 变体(已编辑;来自here):header("Content-Disposition: attachment; filename=file.zip"); header("Content-Type: application/force-download"); header("Content-Length: " . filesize($file)); header("Connection: close"); 2:Apache 解决方案,不涉及 PHP:让 Apache 为文件提供服务,并使用
.htaccess为同一文件提供不同的 URL(可以编写多种方法)。在性能方面,类似于让客户下载example.com/file.zip,由Apache服务器提供服务。-
3:另一种 PHP 解决方案。这可能会起作用:
$myfile = file_get_contents("file.zip"); echo $myfile;但这不会要求 PHP 将整个内容加载到内存中吗? (这在性能方面会很糟糕!)
-
4:只需按照File with a short URL downloaded with original filename 中的说明进行
header("Location: /abcd/file.zip");重定向。此解决方案的问题:这会泄露文件的实际位置
example.com/abcd/file.zip发给不想要的最终用户(然后他们可以使用或共享此 URL 而无需经过身份验证)...
但另一方面,它对 CPU 来说要轻得多,因为 PHP 只是重定向请求而不是传递文件本身。
下载时测得的 CPU 使用率:10.6%。
注意:readfile 文档说:
readfile() 不会出现任何内存问题,即使在发送大文件时也是如此。如果遇到内存不足错误,请确保使用 ob_get_level() 关闭输出缓冲。
但我想 100% 确定它不会比纯 Apache 解决方案更慢/更占用 CPU/RAM。
【问题讨论】:
-
为什么不对这两种解决方案进行基准测试?
-
如果你想确定,就测试一下。
-
我认为这可能是众所周知的@akond,并且会成为将来参考的有用答案。而且,我还不够 linux-benchmarking-tools-connoisseur 做一个精确的有意义的测试。
-
您能否具体说明您考虑使用 PHP 来处理您的问题中的文件下载的原因?实际上,
header调用对于服务器来说是肤浅的,因为它们是发送给客户端的指令,用于描述客户端应如何处理响应。假设readfile是使用的方法,那么导致“缓慢”的唯一header将是content-length,因为使用filesize需要系统调用,而不是必需的header。其余的标头理论上可以在.htaccess中定义,并且与 PHP 中的效果相同。 -
@fyrye:我正在使用 PHP 1)登录我自己的数据库,令牌 ID
f6zDaq(与用户关联)的文件已被很好地下载 2)检查令牌 ID在提供文件之前匹配数据库中的用户...如果除了 PHP 之外还有其他方法可以做到这一点(直接使用 Apache / .htaccess),我也很感兴趣。
标签: php apache .htaccess download