Implementing Front Controller Pattern in PHP: How to Route All URLs Through index.php Using .htaccess


2 views

Modern PHP frameworks like Laravel, Symfony, and CodeIgniter all implement a front controller pattern where all HTTP requests are routed through a single entry point (typically index.php). This approach enables clean URLs and centralized request handling.

Here's the most effective way to implement this using Apache's mod_rewrite:


RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [QSA,L]

For those using Nginx, the equivalent configuration would be:


location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Your index.php file should then process the request URI:


The error message you encountered ("Invalid URI in request") typically occurs when:

  • The .htaccess file isn't in the correct directory
  • Apache's AllowOverride isn't set to All
  • There are syntax errors in the rewrite rules

Here's a more sophisticated router implementation:


routes[$pattern] = $handler;
    }
    
    public function dispatch() {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        foreach ($this->routes as $pattern => $handler) {
            if (preg_match("#^$pattern$#", $uri, $matches)) {
                array_shift($matches);
                return call_user_func_array($handler, $matches);
            }
        }
        http_response_code(404);
        echo '404 Not Found';
    }
}

$router = new Router();
$router->addRoute('/products/(\d+)', function($id) {
    echo "Showing product $id";
});
$router->dispatch();

While the front controller pattern is powerful, consider these optimizations:

  • Cache .htaccess rules using RewriteMap for high-traffic sites
  • Implement opcode caching (OPcache) for PHP
  • Use a compiled router like FastRoute for better performance

When building modern PHP applications - especially MVC frameworks - we often need all requests to be processed by a single entry point (typically index.php) while maintaining clean, SEO-friendly URLs. The challenge is configuring the web server to handle this routing properly.

The solution primarily involves Apache's mod_rewrite module. Here's the most effective .htaccess configuration I've found after extensive testing:


RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

This:
1. Checks if the requested file doesn't exist (!-f)
2. Checks if the requested directory doesn't exist (!-d)
3. Routes everything to index.php while preserving query strings (QSA) and making this the last rule (L)

Based on the original question's error logs, two key issues emerged:


[error] [client 127.0.0.1] Invalid URI in request GET / HTTP/1.1
[error] [client 127.0.0.1] Invalid URI in request GET /abc HTTP/1.1

Apache Version Differences


# For Apache 2.2.4 (older versions)
RewriteRule ^(.*)$ /index.php [QSA,L]

# For Apache 2.2.11+ (modern versions)
RewriteRule ^(.*)$ index.php [QSA,L]

The leading slash requirement was removed in later versions. Always test with your specific Apache version.

Here's a full working example that demonstrates URL routing:



For production applications, consider these enhancements:


# Handle trailing slashes consistently
RewriteCond %{REQUEST_URI} ^(.+)/$
RewriteRule ^ %1 [R=301,L]

# Exclude common static files from rewriting
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|ico)$ [NC]

Most PHP frameworks like Laravel and Symfony use similar principles but with more sophisticated routers. Here's how they typically structure their .htaccess:


RewriteEngine On
RewriteCond %{REQUEST_URI} ^/index\.php [NC,OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.php [L]