How to Route Clean PHP URLs to a Controller Without Exposing index.php

​When building a custom PHP MVC application without a framework like Laravel or Symfony, one of the most essential features you need is clean, user-friendly URLs.

​For example, instead of serving a page via [example.com/index.php?page=details&domain=example.com](https://example.com/index.php?page=details&domain=example.com),

you want users and search engines to see [example.com/details/example.com](https://example.com/details/example.com).

​In this guide, you will learn how to implement a production-ready Front Controller Pattern using Apache .htaccess and PHP to route dynamic requests seamlessly.

​Key Requirements for Clean URL Routing

​To make custom URL routing work seamlessly in PHP, your application must fulfill these criteria:

  • Clean Browser URLs: Internal rewrites should handle requests without showing index.php in the browser address bar.
  • Bypass Static Files: Requests for actual files (like robots.txt, sitemap.xml, CSS, JS, and images) must be served directly.
  • Preserve Query Strings: Query parameters like ?ref=123 or ?sort=asc must automatically pass through to PHP without extra flags.
  • Normalize Trailing Slashes: Prevent duplicate content issues by automatically redirecting URLs ending with a /.

​Step 1: The .htaccess Configuration

​Create or update your .htaccess file in your project’s root directory with the following code:

apache 

RewriteEngine On

# 1. Force removal of trailing slashes (preserves actual directories)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^(.+)/$
RewriteRule ^ %1 [R=301,L]

# 2. Redirect explicit direct browser requests for index.php to the clean URL
RewriteCond %{THE_REQUEST} \s/index\.php[?\s] [NC]
RewriteRule ^index\.php$ / [R=301,L]

# 3. Serve existing files and directories directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# 4. Route all dynamic requests to index.php internally
RewriteRule ^(.*)$ index.php [L]

Technical Breakdown:

THE_REQUEST Rule: Using THE_REQUEST is crucial because it inspects the raw HTTP request line sent by the browser. It detects explicit browser requests for /index.php while ignoring Apache’s internal rewrite to index.php, allowing the application to redirect only direct requests to the clean URL.

​Step 2: Parsing Clean URLs and Dynamic Parameters in PHP

​Now that Apache routes all traffic through index.php, you can inspect $_SERVER[‘REQUEST_URI’] to build a dynamic router capable of handling multiple route parameters:


<?php
// 1. Get the requested path without query strings
$requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// 2. Trim slashes, filter empty segments, and re-index array keys using array_values()
$rawSegments  = explode('/', trim($requestUri, '/'));
$pathSegments = array_values(array_filter($rawSegments));

// 3. Extract Controller and Parameters dynamically
$controllerName = !empty($pathSegments[0]) ? $pathSegments[0] : 'home';

// Slice the array to safely extract all remaining sub-paths/parameters
$params = array_slice($pathSegments, 1);

// 4. Router Dispatcher
switch ($controllerName) {
    case 'home':
        echo "Welcome to the Homepage!";
        break;

    case 'details':
        $domain    = $params[0] ?? null;
        $subAction = $params[1] ?? null;

        if ($domain) {
            echo "Loading details for: " . htmlspecialchars($domain);
            if ($subAction) {
                echo " | Sub-action: " . htmlspecialchars($subAction);
            }
        } else {
            http_response_code(400);
            echo "400 Bad Request: Missing required parameters.";
        }
        break;

    default:
        http_response_code(404);
        echo "404 Page Not Found";
        break;
}

Common Pitfalls to Avoid

  • Missing Mod_Rewrite: Ensure Apache’s mod_rewrite module is enabled on your server (a2enmod rewrite on Linux).
  • AllowOverride None: If your .htaccess rules are ignored, verify that your Apache VirtualHost configuration sets AllowOverride All.
  • Hardcoded Links: Update your HTML navigation links to relative clean paths (e.g., <a href=”/details/example.com”>) instead of pointing directly to index.php.

Also read : How to Embed Interactive Plotly Graphs in Python HTML Emails (Fixed)

1 thought on “How to Route Clean PHP URLs to a Controller Without Exposing index.php”

Leave a Comment