Bas*_*asj 3 php apache .htaccess download
我需要向客户交付大文件file.zip(约2 GB),并为每个客户提供唯一的URL。然后,我将(带有.htaccess)客户下载链接重定向example.com/download/f6zDaq/file.zip到类似
example.com/download.php?id=f6zDaq&file=file.zip
Run Code Online (Sandbox Code Playgroud)
但是由于文件很大,所以我不希望PHP处理下载(而不只是让Apache处理下载)成为我服务器的CPU / RAM性能问题。毕竟,要求PHP执行此操作涉及一个新层,因此,如果处理不正确,可能会导致此类问题。
问题:在以下解决方案中,最佳实践是哪一个?(特别是在CPU / RAM方面)?
1:PHP解决方案 application/download
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename=file.zip');
readfile("/path/to/file.zip");
Run Code Online (Sandbox Code Playgroud)1之二:的PHP解决方案application/octet-stream(来自此页面的示例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");
Run Code Online (Sandbox Code Playgroud)1ter:PHP溶液application/octet-stream(来自来这里):
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");
Run Code Online (Sandbox Code Playgroud)1quater:另一个PHP变体,具有application/force-download(已编辑;来自此处):
header("Content-Disposition: attachment; filename=file.zip");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($file));
header("Connection: close");
Run Code Online (Sandbox Code Playgroud)2:Apache解决方案,不涉及PHP:让Apache提供文件,并使用.htaccess为同一文件提供不同的URL(可以用多种方式编写)。在性能方面,这类似于让客户下载example.com/file.zipApache服务器提供的服务。
3:另一个PHP解决方案。这可能会起作用:
$myfile = file_get_contents("file.zip");
echo $myfile;
Run Code Online (Sandbox Code Playgroud)
但这不是要PHP将全部内容加载到内存中吗?(就性能而言,这是不好的)
注意:readfile doc说:
即使单独发送大文件,readfile()也不会出现任何内存问题。如果遇到内存不足错误,请确保使用ob_get_level()关闭输出缓冲。
但我想100%确保不会比纯Apache解决方案慢/更多的CPU / RAM饥饿。
您可以.htaccess在保留永久链接结构的同时将请求重定向到文件:
RewriteEngine On
RewriteBase /
RewriteRule ^download\/([^\/]+)\/file.zip download.php?id=$1 [L,NC]
Run Code Online (Sandbox Code Playgroud)
然后在中download.php,您可以检查提供的ID是否有效:
// Path to file
$file = 'file.zip';
// If the ID is valid
if ($condition) {
header("Content-Disposition: attachment; filename=\"" . basename($file) . "\"");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($file));
header("Connection: close");
} else {
// Handle invalid ids
header('Location: /');
}
Run Code Online (Sandbox Code Playgroud)
当用户访问有效的url时http://example.com/download/f6zDaq/file.zip,将开始下载并关闭连接。
如果用户访问无效的URL,他们将被重定向到主页。
正如使用 PHP 提供文件的最快方法中提到的,我最终这样做了:
apt-get install libapache2-mod-xsendfile
a2enmod xsendfile # (should be already done by previous line)
Run Code Online (Sandbox Code Playgroud)
然后我将其添加到apache2.conf:
<Directory />
AllowOverride All
Require all granted
XSendFile on
XSendFilePath /home/www/example.com/files/
</Directory>
Run Code Online (Sandbox Code Playgroud)
然后我做了service apache2 restart并将其包含在.htaccess:
RewriteRule ^(.*)$ download.php?file=$1 [L,QSA]
Run Code Online (Sandbox Code Playgroud)
这在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 . '"');
Run Code Online (Sandbox Code Playgroud)
注意:奇怪的是,即使我已经AllowOverride All在 VirtualHost 中启用apache2.conf,这样做:
XSendFile on
XSendFilePath /home/www/example.com/files/
Run Code Online (Sandbox Code Playgroud)
只是在/home/www/example.com/.htaccess或/home/www/example.com/files/.htaccess文件中不起作用(它失败了xsendFilePath not allowed here)。
基准: