使用download.php下载文件

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饥饿。

Chi*_*ung 5

您可以.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,他们将被重定向到主页。


Bas*_*asj 0

正如使用 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)。

基准:

  • 下载时占用 10.6% 的 CPU,就像我使用 Apache 直接下载文件一样(根本没有 PHP),所以一切都很好!