使用download.php下载文件 [英] Downloading files with download.php
问题描述
我需要向客户交付大文件,如 file.zip
(约2 GB),并为每个客户提供唯一的URL.然后,我将(使用 .htaccess
重定向)客户下载链接 example.com/download/f6zDaq/file.zip
到类似的内容
I need to deliver big files like file.zip
(~2 GB) to customers, with a unique URL for each customer. Then I will redirect (with .htaccess
) a customer download link example.com/download/f6zDaq/file.zip
to something like
example.com/download.php?id=f6zDaq&file=file.zip
但是,由于文件很大,因此我不希望PHP处理下载(而不只是让Apache处理下载)成为我服务器的CPU/RAM性能问题.毕竟,要求PHP执行此操作涉及一个新层,因此,如果执行不正确,它可能会引起此类问题.
But as the files are big, I don't want the fact that PHP processes the downloading (instead of just letting Apache handle it) to be a CPU / RAM performance issue for my server. After all, asking PHP to do it involves a new layer, so it might cause such an issue, if not done properly.
问题:在以下解决方案中,哪种是最佳实践?(尤其是在CPU/RAM方面)?
Question: among the following solutions, which one(s) are the best practice? (in particular, in terms of CPU/RAM)?
-
1:具有
application/download
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename=file.zip');
readfile("/path/to/file.zip");
下载时测得的CPU使用率:13.6%.
CPU usage measured while downloading: 13.6%.
1bis:具有 application/octet-stream
的PHP解决方案(来自
1bis: PHP solution with application/octet-stream
(coming from Example #1 of this page)
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");
1之三:具有 application/octet-stream
的PHP解决方案(来自此处):
1ter: PHP solution with application/octet-stream
(coming from 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");
1之四:另一个具有 application/force-download
的PHP变体(已编辑;来自此处):
1quater: Another PHP variant with application/force-download
(edited; coming from 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(可以用多种方式编写).在性能方面,这类似于让客户下载由Apache服务器提供的 example.com/file.zip
.
2: Apache solution, no PHP involved: let Apache serve the file, and use .htaccess
to provide different URL for the same file (many ways to do it can be written). In terms of performance, it's similar to let the customer download example.com/file.zip
, served by Apache server.
3:另一个PHP解决方案.这可能会起作用:
3: Another PHP solution. This would probably work:
$myfile = file_get_contents("file.zip");
echo $myfile;
但是这不会要求PHP将全部内容加载到内存中吗?(就性能而言,这是很糟糕的!)
but wouldn't this ask PHP to load the whole content in memory? (which would be bad in terms of performance!)
4:只需执行 header("Location:/abcd/file.zip");
重定向,如
4: Just do a header("Location: /abcd/file.zip");
redirection as explained in File with a short URL downloaded with original filename.
此解决方案的问题:这会公开文件的实际位置
Problem with this solution: this discloses the actual location of the file
example.com/abcd/file.zip
不需要的最终用户(然后该用户无需身份验证即可使用或共享此URL)...
to the end user (who can then use or share this URL without authentification) which is not wanted...
但是,另一方面,由于PHP只是重定向请求,而不是传递文件本身,因此对CPU来说要轻得多.
But on the other hand, it is much lighter for the CPU since PHP just redirects the request and doesn't deliver the file itself.
下载时测得的CPU使用率:10.6%.
CPU usage measured while downloading: 10.6%.
注意: readfile 文档说:
Note: the readfile doc says:
readfile()本身不会出现任何内存问题,即使在发送大文件时也是如此.如果遇到内存不足错误,请确保使用ob_get_level()关闭输出缓冲.
readfile() will not present any memory issues, even when sending large files, on its own. If you encounter an out of memory error ensure that output buffering is off with ob_get_level().
但是我想100%确保它不会比纯Apache解决方案慢/更多的CPU/RAM饥饿.
推荐答案
<Directory />
AllowOverride All
Require all granted
XSendFile on
XSendFilePath /home/www/example.com/files/
</Directory>
然后,我重新启动了 service apache2
,并将其包含在 .htaccess
中:
I then did service apache2 restart
and included this in .htaccess
:
RewriteRule ^(.*)$ download.php?file=$1 [L,QSA]
,这在 download.php
中:
header("X-Sendfile: /home/www/example.com/files/hiddenfolder_w33vbr0upk80/" . $file);
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $file . '"');
NB:奇怪的是,即使我在 apache2.conf
VirtualHost中启用了 AllowOverride All
,也是这样做的:
NB: strangely, even I have AllowOverride All
enabled in the apache2.conf
VirtualHost, doing this:
XSendFile on
XSendFilePath /home/www/example.com/files/
仅在/home/www/example.com/.htaccess
或/home/www/example.com/files/.htaccess
文件中(由于 xsendFilePath不允许,此处失败
).
just in the /home/www/example.com/.htaccess
or /home/www/example.com/files/.htaccess
file didn't work (it fails with xsendFilePath not allowed here
).
基准:
- 下载时为10.6%的CPU,就像我直接用Apache直接下载文件(完全没有PHP)一样,所以一切都很好!
这篇关于使用download.php下载文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!