Skip to content

Instantly share code, notes, and snippets.

@teameh
Last active December 19, 2019 12:57
Show Gist options
  • Save teameh/126048fba8822450841e2976698ffa82 to your computer and use it in GitHub Desktop.
Save teameh/126048fba8822450841e2976698ffa82 to your computer and use it in GitHub Desktop.
Silex - Let NGINX handle static files after authentication with PHP
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/project/web;
index index.php;
# catches internal redirects from php with 'X-Accel-Redirect' header
location /private_admin_files {
# and forwards them to this path:
alias /var/www/project/src/statics/admin
internal;
}
location / {
# Check if requested file is present and use if for procesing.
# Otherwise, fall back to index.php
try_files $uri /index.php$is_args$args;
}
location ~ \.php$ {
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.*)$;
# Check if requested file is present and use if for procesing.
# Otherwise, fall back to index.php
try_files $uri /index.php$is_args$args;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
# serve index.php in case '/' is requested
fastcgi_index index.php;
# use socket
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi_params;
}
}
<?php
use Silex\Application;
use Symfony\Component\HttpFoundation\Response;
class StaticFileController
{
/**
* @param Application $app
* @param string $file filename of file to serve
* @param string $folder folder of the file to serve
* @param string $virtiualXAccelRedirPath virtual X-Accel-Redirect path as used in vhost
*
* This will return an empty response with the right X-Accel-Redirect header.
* NGINX will use this header and will match it's value against all location as defined
* in it's vhost.
*
* For example:
*
* $file = 'admin.js'
* $folder = __DIR__ . '/../statics/admin/'
* $virtiualXAccelRedirPath = '/private_admin_files'
*
* NGINX vhost config has a location block like:
*
* location /private_admin_files {
* alias /path/to/project/src/statics/admin/
* internal;
* }
*
* This method will send a response with
*
* X-Accel-Redirect: /private_admin_files/admin.js
*
* And NGINX will rewrite it to
*
* /path/to/project/src/statics/admin/admin.js internally
*
* and will serve the requested file without much PHP overhead!
*
* @return Response
*/
public function getFile(Application $app, $file = '', $folder = '', $virtiualXAccelRedirPath = '')
{
if (empty($file) || empty($folder) || empty($virtiualXAccelRedirPath)) {
$app->abort(400);
}
// add slash if string does not end in slash
if (substr($folder, -1) !== '/') {
$folder .= '/';
}
if (substr($virtiualXAccelRedirPath, -1) !== '/') {
$virtiualXAccelRedirPath .= '/';
}
if (!is_readable($folder . $file)) {
$app->abort(404, 'file not readible ' . $folder . $file);
}
switch (strtolower(pathinfo($file, PATHINFO_EXTENSION))) {
case 'css' : {
$contentType = 'text/css';
break;
}
case 'js' : {
$contentType = 'application/javascript';
break;
}
case 'xml' : {
$contentType = 'text/xml';
break;
}
case 'svg' : {
$contentType = 'image/svg+xml';
break;
}
default : {
$contentType = 'text/plain';
}
}
return new Response('', 200, [
'X-Accel-Redirect' => $virtiualXAccelRedirPath . $file,
'Content-Type' => $contentType
]);
}
}
use Silex\Application;
use Silex\Api\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class Routing implements ControllerProviderInterface
{
public function connect(Application $app)
{
$controllers = $app['controllers_factory'];
$controllers->get('/', 'IndexController::getPage');
// ... more controllers
$app->mount('/admin', new AdminRouting());
return $controllers;
}
}
use Silex\Application;
use Silex\Api\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminRouting implements ControllerProviderInterface
{
public function connect(Application $app)
{
$controllers = $app['controllers_factory'];
$controllers->before(function (Request $request, Application $app) {
// check auth or abort!
});
$controllers->get('/', 'AdminController::getIndex');
$controllers->get('/static/{file}', 'StaticFileController::getFile')
->assert('file', '.+')
->value('folder', __DIR__ . '/../statics/admin')
->value('virtiualXAccelRedirPath', '/private_admin_files');
return $controllers;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment