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

关于申请

我正在使用PHP的电子商务应用程序。 为了保持URL的安全,产品下载链接保留在PHP之后。 有一个文件,说download.php,通过GET接受几个参数,并validation他们对数据库。 如果一切顺利的话,它使用PHP中的readfile()函数来提供文件。

关于问题

现在问题来了,当传递给readfile()的文件大于在php.ini中设置的内存限制因为这个应用程序将被共享主机上的许多用户使用,我们不能继续改变php.ini设置。

在我们寻找解决方法的努力中,我首先想到的是我们可以在while循环中进行fread()调用,但似乎会强加一些问题,并在此突出显示。 在PHP中可靠地下载大文件

所以我最好的select是检测/检查服务器是否支持X-Accel-Redirect(如果是Nginx)/ X-Sendfile(在Apache的情况下)

如果服务器支持X-Accel-Redirect / X-Sendfile,我可以使用它们,并在其他块我可以使系统pipe理员意识到由php.ini强制执行的内存限制

理想情况下,我想尽可能使用像X-Accel-Redirect / X-Sendfile这样的服务器端支持,如果这样做不起作用 – 我希望有一个后备代码来读取没有readfile()的文件。

我不确定如何while循环中的readfile()和fread()是不同的,但似乎while循环将创build问题,再次build议在PHP中可靠地下载大文件

希望得到一些帮助,build议,守则,指导。

谢谢阅读。

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

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

但是这个代码只是检查模块是否安装,如果安装但是配置错误会导致错误

另一种可能的方法是通过Apache的.htaccess来设置服务器范围的变量:

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

并检查它的形式php代码:

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

对于nginx来说,通常的想法是一样的 – 只需要通过HTTP头或CGI / FastCGI变量将状态变量的值传递给后端即可。

readfile不占用大量的内存。 它打开文件,读取一小部分,将该部分写入浏览器,然后重新使用内存进行下一次读取。 这和在while循环中使用fread + echo是一样的。 你不会被内存限制所限制,但是你会受到max_execution_time等的限制。

如果您想使用Web服务器提供的X-Accel-Redirect支持(或类似的功能),请发送如下的头文件(对于Nginx):

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

你的应用程序不能知道服务器是否支持这个。 您需要提供配置选项,以便您的软件的管理员/安装人员可以手动提供这些信息。

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

 <?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(); } } 

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