如何检测PHP中的X-Accel-Redirect(Nginx)/ X-Sendfile(Apache)支持?

mbjcgjjk  于 2023-01-21  发布在  Apache
关注(0)|答案(3)|浏览(131)

关于应用程序

我正在用PHP开发一个电子商务应用程序。为了保证URL的安全,产品下载链接被保存在PHP后面。有一个文件,比如download.php,它通过GET接受一些参数,并在数据库中验证它们。如果一切顺利,它将使用PHP中的readfile()函数提供文件。

问题

现在,当传递给readfile()的文件大于php.ini中设置的内存限制时,问题就来了。由于这个应用程序将被共享主机上的许多用户使用,我们不能依赖于改变php.ini设置。
在我们努力寻找解决方法的过程中,我首先想到可以在while循环中调用fread(),但这似乎会带来一些问题,这里也强调了Downloading large files reliably in PHP

    • 因此,我的最佳选择是检测/检查服务器是否支持X-Accel-Redirect(在Nginx的情况下)/X-Sendfile(在Apache的情况下)**

如果服务器支持X-Accel-Redirect/X-Sendfile,我可以使用它们,在else块中,我可以让系统管理员知道php.ini强制执行的内存限制
理想情况下,我希望尽可能使用服务器端支持,如X-Accel-Redirect/X-Sendfile,如果这不起作用-我希望有一个后备代码来读取文件,而不使用readfile()。
我还不确定while循环中的readfile()和fread()有何不同,但似乎while循环将再次产生问题,如Downloading large files reliably in PHP中所建议的
希望能得到一些帮助、建议、代码、指导。
感谢阅读。

vxf3dgd4

vxf3dgd41#

要检测是否安装了mod_xsendfile apache模块,可以尝试以下代码:

if function_exists('apache_get_modules') 
      && in_array('mod_xsendfile', apache_get_modules()) { 
  header("X-Sendfile"); 
}

但是这段代码只是检查模块是否只安装了,如果安装了但配置错误,可能会导致错误
另一种可能方法是通过Apache的.htaccess设置服务器范围的变量:

<IfModule mod_xsendfile.c>
  <Files *.php>
    XSendFile On
    XSendFileAllowAbove On
    SetEnv MOD_X_SENDFILE_ENABLED 1
  </Files>
</IfModule>

并检查它的形式php代码:

if ($_SERVER['MOD_X_SENDFILE_ENABLED']) {
  Header(...)
}

对于nginx来说,通常的想法是相同的--只需通过HTTP头或CGI/FastCGI变量将status变量的值传递给后端。

kyvafyod

kyvafyod2#

readfile不会占用大量内存。它打开文件,读取一小部分,将该部分写入浏览器,然后在下次读取时重用内存。这与在while循环中使用fread+echo相同。您不会受到内存限制的约束,但会受到max_execution_time等的限制。
如果你想使用你的web服务器提供的X-Accel-Redirect支持(或类似的),发送一个如下的头(Nginx):

header('X-Accel-Redirect: /path/to/file');

您的应用程序无法知道服务器是否支持此功能。您需要提供一个配置选项,以便软件的管理员/安装程序可以手动提供此类信息。

9rygscc1

9rygscc13#

您可以在服务器上设置一个环境变量来控制正确的服务器头文件名称(可能由运营团队或负责脚本/定义服务器环境的任何人设置)。这将适用于任何支持基于头文件的文件服务的堆栈,因为控制该堆栈的人可以做出决定,而您只需从环境中读取头文件。

<?php

/**
 * Method to delegate sending file to webserver
 *
 * Uses environment variable `SERVER_ACCEL_HEADER` to define the specific
 * server header to use to send files from server layer rather than 
 * application layer
 *
 * @param  string $path path to file that should exist
 * @param  bool $die if script should terminate after setting header
 * @return void returns nothing
 */
function sendPathAccel($path, $die=true) {
    $accelHeader = getenv('SERVER_ACCEL_HEADER');
    header("{$accelHeader}: {$path}");
    if($die) { die(); }
}

**警告:**需要注意的是,这不是新手操作,所以要小心。如果服务器环境的负责人不设置它,使用它可能会出很多问题,可能不会工作或可能导致错误,但它简单,快速,我想不出改变它的理由。

相关问题