php - apache用 download.php 下载文件

我需要向客户提供像 file.zip ( ~2 GB ) 这样的大文件,每个客户都有一个。 然后我将( 使用 .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");
    
    
    
    
  • 1bis使用 application/octet-stream 的PHP解决方案(来自的示例 #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解决方案:

    
    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变量:

    
    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将整个内容加载到内存中吗? (这在性能方面会很糟糕)

注:readfile doc表示:

readfile() 不会出现任何内存问题,即使在发送大文件时也不会出现。 如果遇到内存不足错误,请确保输出缓冲与 ob_get_level() 一起关闭。

但是,我想100%肯定它比纯Apache解决方案更慢/需要更多的CPU/内存。

时间:

我会选择 readfile 我使用它多年,从来没有遇到内存问题,即使在 128MB VPS上运行 。

使用PHP意味着你可以轻松处理认证,授权,日志记录,添加和删除用户,过期的URL等等。 你可以使用 .htaccess 实现这一点,但是你必须编写一个相当大的结构来处理这个问题。

你可以使用 .htaccess 将请求重定向到文件,同时保留永久链接结构:


RewriteEngine On


RewriteBase/


RewriteRule ^download/([^/]+)/file.zip download.php?id=$1 [L,NC]



然后在 download.php 中,你可以检查提供的标识是否有效:


//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:/');


}



当用户访问有效的url时 http://example.com/download/f6zDaq/file.zip 下载将开始,并且连接将关闭。

如果用户访问无效的url,他们将被重定向到主页。

您对这些尺寸的文件所面临的最大问题如下,

  • 人们用下载管理器下载它
  • 中断的连接

通常情况下,keep-alive可能是一个坏主意,因为它专门用于下载连接,这可能会阻碍您的网络连接,而且不是允许它们轻松释放。 但是,如果您所有文件都很大,那么,这您对访客的友好度,因为您不希望人们重新下载这些文件。 这些下载将与keep-alive建立可靠的连接,并使客户端更容易恢复,这有助于减少尝试重新下载大量文件的人。

因此,在你提供的选项中,我推荐

1ter

但是,和其他人一样,我仍然建议您测试您的解决方案,最好是从您提供文件的地方以外的位置进行测试。

附录这说除非你必须获得 header 功能,否则使用PHP并不是最好的主意 。 htaccess控制,因为它只是增加了更多的处理能力 。 到目前为止,更好的路径是将文件放在可访问目录中。 htaccess可以重写对文件和文件夹的访问,而不仅仅是PHP脚本。

要创建基于apache的保护下载文件夹,请执行以下操作:


Options +FollowSymLinks


RewriteEngine On


RewriteRule ^/user/files/folder1.*$ http://example.com/userfiles/[R=301,L]



然后,如果需要密码保护,而不是使用 PHP,请使用 Apache ( 它已经安装在大多数PHP安装中) 。 通过将.htaccess文件包括在目标文件夹( 如果动态生成用户,则可能需要创建脚本以为每个新用户生成这些脚本) 中,并确保apache已准备好处理密码,请执行以下操作:


AuthType Basic


AuthName"Authentication Required"


AuthUserFile"/user/password/.htpasswd"


Require valid-user



( 有关详细信息,请参见这里: (设置Apache密码 )

在这个点之后,你要确保密码目录中有一个.htpasswd文件,格式为 username: password/hashedpassword 。

比如:


andreas:$apr1$dHjB0/..$mkTTbqwpK/0h/rz4ZeN8M0


john:$apr1$IHaD0/..$N9ne/Bqnh8.MyOtvKU56j1



现在,假设您不希望他们每次都传递密码,请在下载链接中包含访问权限,


<a href="user:pass@http://example.com/userfiles/myCoolZip.zip">Link (hopefully behind a password-protected interface.)</a> 



[ 注:如果每个文件没有随机分配密码,则不要使用直接密码链接方法。]

或者,如果你基于 root Apache密码管理进行填充,并且你的网站正在使用Apache进行登录过程,他们可能根本不需要链接的 user:pass 部分,已经使用Apache登录 。

注意:

现在,这就是说,人们可以访问共享完整链接( 使用用户名/密码)的文件 。 因此,它们将与你的https服务器( 如果允许,则为 http ) 协议一样安全( 或作为不安全的) 以及你的用户共享或不共享链接 。

通过这种方式,文件将向用户开放,并且可以访问Web的全部功能,这意味着下载程序,浏览器插件,REST调用等等,具体取决于你的用户的用例。 这可以降低安全性,这可能是一个很大的问题,取决于你所承载的内容。 如果你主机上有私人医疗数据(很少的用户,但高安全性,较低的速度要求),我不会这样做的。 如果你主机上是音乐专辑,我会完全这样做( 许多用户,安全性低,要求高速)

节约内存

关于你发送的header,它们不会影响脚本的性能,它们只会指示客户端如何处理服务器响应( 在你的情形中) 你可以 Google header,看看它到底做了什么。

你可能需要了解以下方面: 在PHP中有部分文件下载的良好实现吗 。你可能会感兴趣的事情: 下载范围和下载恢复支持,使用Web服务器插件 pear 包或提供所需功能的库的方法 。

...