Sendfile
Sendfile handles static files, allowing the use of authentication and other features, while the server takes care of delivering the content to the end user.
Modules
| Module | Web Server | Website |
|---|---|---|
X-Accel-Redirect |
nginx |
X-Accel-Redirect is supported by default in nginx. Note: for security, configure a location {} with the internal directive.
|
X-LIGHTTPD-send-file & X-Sendfile2 |
Lighttpd module | https://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file |
X-Sendfile |
Apache | https://tn123.org/mod_xsendfile/ |
Simulator |
Built-in Web Server | The built-in simulator in Inphinit applications allows you to partially simulate the X-Accel-Redirect and X-Sendfile headers in a simple way without needing a full server, making development easier. |
nginx module
nginx compares this URI with its respective directories, as if it were a normal request. Then, it serves the directory that corresponds to the defined root and the URI passed in the header. Example configuration:
location / {
...
location ~ \.php$ {
# Replace by your FPM or FastCGI
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
# It helps libraries detect if a resource is available
fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED on;
set $inphinit_prefix "";
if ($uri != "/index.php") {
set $inphinit_prefix "/public";
}
fastcgi_param SCRIPT_FILENAME $realpath_root$inphinit_prefix$fastcgi_script_name;
}
}
location /protected_files {
root /path/foo/bar;
internal;
}
It is also possible to proxy to another server:
location /protected_files {
proxy_pass http://127.0.0.2;
internal;
}
And in scripts you can use the header, as in the example:
$app->action('GET', '/download', function () {
if (isLoggedIn()) {
header("X-Accel-Redirect: /protected_files/sample.txt");
}
});
Using route pattern:
$app->action('GET', '/download/<file:alnum>.txt', function (App $app, array $params) {
if (isLoggedIn()) {
$name = $params['file']; // From <file:alnum>
header("X-Accel-Redirect: /protected_files/{$name}.txt");
}
});
Lighttpd module
Example of how to enable it in lighttpd:
fastcgi.server = {
".php" => {
"127.0.0.1" => {
# ....
"allow-x-send-file" => "enable"
}
}
}
Example of use:
use Inphinit\Http\Response;
$app->action('GET', '/download/<file:alnum>.txt', function (App $app, array $params) {
if (isLoggedIn()) {
// Content-Disposition
Response::download('download.txt');
header('X-LIGHTTPD-send-file: /path/foo/bar/sample.txt');
}
});
Apache module
To define the path it is necessary to modify server config, virtual host, directory contexts. Example:
<VirtualHost ...>
...
XSendFilePath /path/foo/bar
</VirtualHost>
To enable it, you can do it in any context, including directly in the .htaccess file:
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
XSendFile on
# It helps libraries detect if a resource is available
SetEnv MOD_X_SENDFILE_ENABLED 1
...
Example of use:
use Inphinit\Http\Response;
$app->action('GET', '/download/<file:alnum>.txt', function (App $app, array $params) {
if (isLoggedIn()) {
// Content-Disposition
Response::download('download.txt');
header('X-Sendfile: /path/foo/bar/sample.txt');
}
});
Simulator
Using PHP's built-in web server, it's possible to simulate the X-Accel-Redirect and X-Sendfile headers. No configuration is necessary; simply use the headers. Then, when starting a local server, use ./run serve, allowing the use of:
$app->action('GET', '/download/<file:alnum>.txt', function (App $app, array $params) {
if (isLoggedIn()) {
$name = $params['file'];
header("X-Accel-Redirect: /path/foo/bar/{$name}.txt");
}
});
FileResponse class
The Inphinit\Experimental\Http\FileResponse class can also be used to serve files, relying on environment variables to verify module support. These variables typically must be configured manually.
FileResponse::ACCEL (X-Accel-Redirect):
use Inphinit\Experimental\Http\FileResponse;
$app->action('GET', '/download/<file:alnum>.txt', function (App $app, array $params) {
if (isLoggedIn()) {
$handle = new FileResponse($params['file'], 'output.txt');
try {
// Try serving it with an X-Accel-Redirect header
$handle->send(FileResponse::ACCEL);
} catch (\Exception $ee) {
echo 'Downloads unavailable.';
}
}
});
FileResponse::SENDFILE (X-Sendfile):
$handle = new FileResponse($params['file'], 'output.txt');
try {
// Try serving it with an X-Sendfile header
$handle->send(FileResponse::SENDFILE);
} catch (\Exception $ee) {
echo 'Downloads unavailable.';
}
Evaluating available modules:
$handle = new FileResponse($params['file'], 'output.txt');
try {
// It will try serving with X-Accel-Redirect if available, otherwise it will try using X-Sendfile
$handle->send(FileResponse::ACCEL|FileResponse::SENDFILE);
} catch (\Exception $ee) {
echo 'Downloads unavailable.';
}
Fallback:
The Senfile fallback is an alternative mechanism that should be used only as a last resort and only when absolutely necessary. In the example below, the system first attempts to use X-Accel-Redirect; if that is unavailable, it falls back to X-Sendfile and if neither is supported, it ultimately serves the file directly via PHP:
$handle = new FileResponse($params['file'], 'output.txt');
try {
$handle->send(FileResponse::ACCEL|FileResponse::SENDFILE|FileResponse::FALLBACK);
} catch (\Exception $ee) {
echo 'Downloads unavailable.';
}