Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Simple Request Router via PHP and Apache/.htaccess

I’ve written many articles about how to redirect requests. Even so, I still get questions about how to set up a simple HTTP request router. As in you want to redirect or route all requests to some file or location. This is useful for building CMSs and scripts that handle traffic. For example, WordPress uses a simple request router when permalinks are enabled. For this tutorial, we’ll set this up using Apache/.htaccess and PHP.

This technique is an excellent starting point for making your own (simple) content management system.


How WordPress does it

To get a better idea of what we’re doing here. Let’s look at WordPress, a widely used CMS that many are familiar with. When permalinks are enabled, WordPress redirects all incoming HTTP traffic to the index.php file. To do this, the following bit of .htaccess is added to the site’s root .htaccess file:

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
	RewriteBase /
	RewriteRule ^index\.php$ - [L]
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule . /index.php [L]

Notice the path specified in the RewriteRule, which points to WordPress’ main index.php file. Inside of that file is the following PHP code:

define('WP_USE_THEMES', true);
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

From there WordPress calls wp-blog-header.php, which includes the following bit of conditional PHP logic:

if ( !isset($wp_did_header) ) {

	$wp_did_header = true;

	// Load the WordPress library.
	require_once( dirname(__FILE__) . '/wp-load.php' );

	// Set up the WordPress query.

	// Load the theme template.
	require_once( ABSPATH . WPINC . '/template-loader.php' );


..and it’s off to the races. This code then continues to load all of the required files and scripts necessary for WordPress to output the appropriate post, page, archive, search results or whatever is needed to fulfill the request.

So to sum up WordPress request router:

  1. Use .htaccess code to route all traffic to index.php
  2. index.php then calls wp-blog-header.php
  3. wp-blog-header.php then continues with further logic, etc.

Of course, the PHP and other “logic” employed by WordPress is deep and wide. Feel free to continue down that rabbit hole if you dare (you will learn a LOT, trust me). For this tutorial, we’re going to keep the router logic as simple as possible. You can always modify and extend the basic example to suit your specific project needs.

Build your own simple request router

Now that we’ve seen how WordPress does it, let’s break things down and simplify the routing technique. The goal is to build the simplest PHP router possible. So all incoming traffic will redirect to index.php, which then will route to the necessary PHP files that deliver the page views.

To give you some context, here is what the path structure will look like:


The goal is to keep things super simple. In order to focus on the main point: how to route traffic via PHP and .htaccess. So nothing fancy but this is well-tested and it just works. So you can get the idea and go from there, customizing and extending things however you’d like. Here are three steps to make it happen:

Step 1: Add .htaccess

Create a new folder named app. In it, create an .htaccess file. Add these rules:

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /app/
	RewriteRule ^index\.php$ - [L]
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule . index.php [L,QSA]

This basically is just a simplified version of the WordPress permalink (routing) rules. Notice the RewriteBase specifies our /app/ directory. Collectively these rules redirect all incoming traffic to the root index.php file. Fine-tune as desired.

Step 2: Create index.php

Next, create a file named index.php and place it in the root directory of your project. This will be the main routing switch that handles the conditional loading of files. Inside of index.php, add the following code:


$request_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null;

if ($request_uri === '/app/' || $request_uri === '/app') {
	$route = '/home.php';
} elseif ($request_uri === '/app/about/' || $request_uri === '/app/about') {
	$route = '/about.php';
} elseif ($request_uri === '/app/archive/' || $request_uri === '/app/archive') {
	$route = '/archive.php';

} elseif ($request_uri === '/app/contact/' || $request_uri === '/app/contact') {
	$route = '/contact.php';
} else {
	$route = '/404.php';

require __DIR__ . $route;

No changes need made to this code. What is it doing though. Basically this code grabs the requested path via $_SERVER['REQUEST_URI']. It then checks the path and responds with the appropriate PHP file. For example, requests for /about will be served about.php, and so forth. The logic is very basic, and is very fast.

Step 3: Create the view files

Lastly, create the five view files, 404.php, about.php, archive.php, contact.php, and home.php. Here are the contents of each of these files, respectively:

<?php // 404 Not Found

echo '<h1>404 - Not Found</h1>';
<?php // About Page

echo '<h1>About us</h1>';
<?php // Archive

echo '<h1>Welcome to the archive</h1>';
<?php // Contact

echo '<h1>Contact us!</h1>';
<?php // Homepage

echo '<h1>Welcome to the homepage</h1>';

Again, we’re keeping things super simple, so the above code is just enough to know that things are working. Obviously you can build out the page views as much as needed. Once you see how things work, you can rename pages, add pages, etc.

Testing in a browser

We now can upload the /app/ directory to the server and test that everything is working. In a browser, you can visit the following pages:

  • https://example.com/
  • https://example.com/about/
  • https://example.com/archive/
  • https://example.com/contact/
  • https://example.com/404

Remember to replace example.com with your actual domain. Each page should display the corresponding view file. Any request not included in the above list will result in the 404 view displayed.

Note: If you’re getting 404 “Not Found” errors, it could be due to server configuration. For more information, check the accepted answer on this post.


Download the finished app here. No license just go have fun and build stuff :)

Download Simple Request RouterVersion 1.0 ( 1.83 KB ZIP )

Usage: Unzip download file, upload /app/ to your server, and visit in a browser.

About the Author
Jeff Starr = Web Developer. Book Author. Secretly Important.
GA Pro: Add Google Analytics to WordPress like a pro.
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
BBQ Pro: The fastest firewall to protect your WordPress.
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.