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 downloa
readfile does not take up a large amount of memory. It opens the file, reads a small portion, writes that portion to the browser and then reuses the memory for the next read. It's the same as using fread+echo in a while loop. You will not be constrained by memory-limits, but you will be limited by max_execution_time and such.
If you want to use X-Accel-Redirect support (or similar) provided by your web server, send a header like this (for Nginx):
header('X-Accel-Redirect: /path/to/file');
Your application cannot know if the server supports this. You will need to provide a configuration option so the admin/installer of your software can provide such information manually.
You could set an environment variable on the server that controls the correct server header name (probably setup by ops team or whoever is responsible for scripting / defining server environment). This would lend itself to any stack supporting Header based file serving because the people in control of that stack are then enabled to make decisions, whilst you just read in from the environment the 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(); }
}
Warning: It should be noted that this is not a novice move, so be careful. A Lot could go wrong using this if the people in charge of the server environment do not setup it probably won't work or may cause errors, but it's simple, fast and I can't think of a reason to change it.
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.