使用 download.php 下载文件 [英] Downloading files with download.php

查看:33
本文介绍了使用 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");

  • 1ter:带有 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");
    

  • 1quater:另一个带有 application/force-download 的 PHP 变体(已编辑;来自此处a>):

  • 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(可以写很多方法).在性能方面,类似于让客户下载example.com/file.zip,由Apache服务器提供服务.

  • 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...

    但另一方面,它对 CPU 来说要轻得多,因为 PHP 只是重定向请求而不是传递文件本身.

    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 文档说:

    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 需求.

    推荐答案

    使用 PHP 提供文件的最快方法,我终于做到了:

    apt-get install libapache2-mod-xsendfile
    a2enmod xsendfile  # (should be already done by previous line)
    

    然后我在 apache2.conf 中添加了这个:

    Then I added this in apache2.conf:

    <Directory />
      AllowOverride All
      Require all granted
      XSendFile on
      XSendFilePath /home/www/example.com/files/
    </Directory>
    

    然后我做了 service apache2 restart 并将其包含在 .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 . '"');
    

    注意:奇怪的是,即使我在 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 not allowed here 而失败).

    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).

    基准:

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

    这篇关于使用 download.php 下载文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆