Skip to main content

Static Files with Modern Routing

Serve static assets (CSS, JavaScript, images, fonts, etc.) directly from a folder with automatic MIME type detection and caching headers.

Basic Usage

<?php
require_once 'vendor/autoload.php';

use PhpCompatible\Router\Router;

Router::run(function() {
// Serve static files from /assets folder at /assets URL
Router::staticFolder(__DIR__ . '/assets', '/assets');

Router::get('/', function() {
return 'Home';
});
});

URL Mapping

The Router::staticFolder() method maps URL paths to files in your static folder:

/public/
├── css/
│ └── style.css → /assets/css/style.css
├── js/
│ └── app.js → /assets/js/app.js
├── images/
│ └── logo.png → /assets/images/logo.png
└── fonts/
└── roboto.woff2 → /assets/fonts/roboto.woff2

Options

Cache Control

By default, static files are cached for 24 hours. Customize this:

use PhpCompatible\Router\Router;

Router::run(function() {
// Cache for 1 week
Router::staticFolder(__DIR__ . '/public', '/assets', array(
'cache_time' => 604800
));

// No caching (development)
Router::staticFolder(__DIR__ . '/public', '/assets', array(
'cache_time' => 0
));

// Cache for 1 year (versioned assets)
Router::staticFolder(__DIR__ . '/public', '/assets', array(
'cache_time' => 31536000
));
});

Allowed Extensions

Restrict which file types can be served:

Router::run(function() {
// Only serve CSS, JS, and images
Router::staticFolder(__DIR__ . '/public', '/assets', array(
'allowed_extensions' => array('css', 'js', 'png', 'jpg', 'gif', 'svg', 'webp')
));

// Only serve fonts
Router::staticFolder(__DIR__ . '/fonts', '/fonts', array(
'allowed_extensions' => array('woff', 'woff2', 'ttf', 'otf', 'eot')
));
});

Multiple Static Folders

use PhpCompatible\Router\Router;

Router::run(function() {
// Serve different asset types from different folders
Router::staticFolder(__DIR__ . '/assets/css', '/css');
Router::staticFolder(__DIR__ . '/assets/js', '/js');
Router::staticFolder(__DIR__ . '/assets/images', '/images');
Router::staticFolder(__DIR__ . '/node_modules', '/vendor', array(
'allowed_extensions' => array('css', 'js', 'map')
));

// Application routes
Router::get('/', function() {
return '<link rel="stylesheet" href="/css/style.css">';
});
});

Complete Example

<?php
require_once 'vendor/autoload.php';

use PhpCompatible\Router\Router;

Router::run(function() {
// Static assets
Router::staticFolder(__DIR__ . '/public', '/assets');

// API routes
Router::group('/api', function() {
Router::get('/users', function() {
return array('users' => array());
});
});

// Web routes
Router::get('/', function() {
return file_get_contents(__DIR__ . '/views/home.html');
});
});

Project Structure

/myapp
├── public/
│ └── index.php # Entry point
├── assets/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── app.js
│ └── images/
│ └── logo.png
├── views/
│ └── home.html
└── vendor/

Security

The Router::staticFolder() method includes security measures:

Directory Traversal Prevention

Attempts to access files outside the static folder are blocked:

// URL: /assets/../../../etc/passwd
Router::staticFolder(__DIR__ . '/public', '/assets');
// Result: 404 Not Found

Real Path Validation

The function uses realpath() to resolve symbolic links and ensure files are within the allowed folder.

MIME Types

The router automatically detects MIME types based on file extension:

ExtensionMIME Type
.csstext/css
.jstext/javascript
.jsonapplication/json
.pngimage/png
.jpgimage/jpeg
.svgimage/svg+xml
.woff2font/woff2

Production Web Server

For production, configure your web server to serve static files directly for better performance.

Apache

RewriteEngine On

# If the file exists in assets, serve it directly
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^assets/(.*)$ assets/$1 [L]

# Otherwise, route to PHP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]

Nginx

location /assets {
alias /var/www/html/assets;
expires 1y;
add_header Cache-Control "public, immutable";
}

location / {
try_files $uri $uri/ /index.php?url=$uri&$args;
}