How to detect X-Accel-Redirect (Nginx) / X-Sendfile (Apache) support in PHP?

rahul286 picture rahul286 · Oct 26, 2010 · Viewed 11.5k times · Source

About Application

I am working on an e-commerce application in PHP. To keep URL's secure, product download links are kept behind PHP. There is a file, say download.php, which accepts few parameter via GET and verifies them against a database. If all goes well, it serves file using readfile() function in PHP.

About Problem

Now problem comes when file to be passed to readfile() is larger than memory limit set in php.ini As this application will be used by many users on shared-hosting we cannot relay on altering php.ini settings.

In our effort to find workarounds, I first thought we can go for fread() calls in while loop but it seems that will impose problems as well as highlighted here Downloading large files reliably in PHP

So my best option is to detect/check if server supports X-Accel-Redirect (in case of Nginx) / X-Sendfile (in case of Apache)

If server supports X-Accel-Redirect / X-Sendfile, I can use them and in else block I can make system admin aware about memory limit enforced by php.ini

Ideally, I want to use server side support like X-Accel-Redirect / X-Sendfile wherever possible, and if that doesn't work - I would like to have a fallback code to read files without readfile().

I am not yet sure as how readfile() and fread() in while loop are different but seems while loop will create problem, again, as suggested in Downloading large files reliably in PHP

Hope to get some help, suggestions, codes, guidance.

Thanks for reading.

Answer

Vadim picture Vadim · Oct 28, 2010

To detect if the mod_xsendfile apache module installed, you can try this code:

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

But this code just check if the module installed only, that can cause errors if it's installed but configured wrongly

another possible way to do this to setup server-wide variable through Apache's .htaccess:

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

and check it form php code:

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

The common idea is the same for nginx - just pass the value of status variable to backend via HTTP-header or CGI/FastCGI variable.