A very simple url manager/rewriter/router

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

A very simple url manager/rewriter/router

Post by s.dot »

This fit my needs perfectly and is very simple and allows for a great amount of flexibility. This will allow me to write any amount of pretty url's with unlimited depth while maintaining a single directory structure for my files.

Example URL: example.com/foo-bar/ would use /foo-bar.php
Example URL: example.com/foo-bar/string/ would use /foo-bar_string.php
Example URL: example.com/foo-bar/string/subsection would use /foo-bar_string_subsection.php
Example URL: example.com/a/b/c/d/e/f/g/h/i would use /a_b_c_d_e_f_g_h_i.php

This file should be used as index.php.

The following .htaccess rules should be used (thanks to requinix @ forums.devnetwork.net)
[text]RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.*) index.php [L][/text]


$_GET and $_POST will still be abailable in their usual manner

Code: Select all

<?php

/**
 * A very simple URL manager/rewriter/router, set this file as index.php
 * With .htaccess rule, allows any length of "pretty URL's" to be written and 
 * funneled to this index.php and routed to their actual scripts.
 *
 * For example, a URL of /foo-bar/ would be directed to /foo-bar.php
 * For example, a URL of /foo-bar/example/ would be directed to 
 *     /foo-bar_example.php
 * For example a URL of /foo-bar/example/detail/subsection/ would be directed 
 *     to /foo-bar_example_detail_subscection.php
 *
 * The .htacess file should look like this: (thanks to requinix @ forums.devnetwork.net)
 * 
 * RewriteEngine On
 * RewriteCond %{REQUEST_FILENAME} !-f
 * RewriteCond %{REQUEST_FILENAME} !-d
 * RewriteRule ^/?(.*) index.php [L]
 *
 * @file	index.php
 * @author	Scott Martin <sjm.dev1 -[at]-gmail-[dot]- com>
 * @date	Feb 13th, 2013
 * @package	None
 */
 
if (!empty($_SERVER['REQUEST_URI']))
{
	//to avoid recursion, actual index content must be in separate script
	if ($_SERVER['REQUEST_URI'] == '/' || $_SERVER['REQUEST_URI'] == '/index')
	{
		require_once 'index_content.php';
		exit;
	}
	
	//request uri will be available and stored in $fileName
	$fileName = $_SERVER['REQUEST_URI'];
	
	//get rid of the query string if present (it is still available in $_GET)
	if (strpos($fileName, '?') !== false)
	{
		$fileName = strtok($fileName, '?');
	}
	
	//replace beginning and trailing slashes
	$fileName = trim($fileName, '/');
	
	//replace slashes with underscores, and lowercase
	$fileName = strtolower(str_replace('/', '_', $fileName));
	
	//check for appropriate characters and file exists
	if (preg_match('#^[a-zA-Z0-9_-]+$#', $fileName) && file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $fileName . '.php'))
	{
		require_once $_SERVER['DOCUMENT_ROOT'] . '/' . $fileName . '.php';
		exit;
	}
}

//if we reach this point, we send a 404 header
header('HTTP/1.0 404 Not Found');
require_once '404.php';
exit;
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: A very simple url manager/rewriter/router

Post by Christopher »

s.dot wrote:Example URL: example.com/a/b/c/d/e/f/g/h/i would use /a_b_c_d_e_f_g_h_i.php
This part confuses me. Why not just have the URL example.com/a_b_c_d_e_f_g_h_i and use the / for actual directory separators? Seems confusing. Or reverse it and use pear style naming so example.com/a_b_c_d_e_f_g_h_i would load /a/b/c/d/e/f/g/h/i.php?
(#10850)
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: A very simple url manager/rewriter/router

Post by s.dot »

I am doing a quick just for fun site. I just wanted a single directory for the files, and a way to map the structured url to the file it would use. /Category/Pagename would look much better than /category_pagename and allows me to maintain a pseudo directory structure.

Works for my purposes, even if it's not standard practices.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
twinedev
Forum Regular
Posts: 984
Joined: Tue Sep 28, 2010 11:41 am
Location: Columbus, Ohio

Re: A very simple url manager/rewriter/router

Post by twinedev »

There is a problem with your preg_match in that it is checking for a single instance of the class of [a-zA-Z0-9_-] to match ANYWHERE in $filename.

You should do:

Code: Select all

preg_match('/^[a-z0-9_-]+$/i', $fileName)
which says match one or more of the class, anchored to both the start and end of the string.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: A very simple url manager/rewriter/router

Post by s.dot »

Good catch!

I wanted to use ctype_alnum but it won't allow for _ and -. I don't like using a regex there. I'll update the main post now.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: A very simple url manager/rewriter/router

Post by Christopher »

Here is one I have used in the past, but it uses PATH_INFO instead. I modified it to look/work more like yours and added the / - translation you do.

Code: Select all

$ConfigArray = array(
	'path' => dirname(__FILE__) . '/pages/',
	'index' => 'index_content',
	'error' => '404',
	);

$fileName = isset($_SERVER['PATH_INFO']) ? trim($_SERVER['PATH_INFO'], '/.') : '';
if ($fileName == '') {
	$fileName = $ConfigArray['index'];
}

//replace slashes with underscores, and lowercase
$fileName = strtolower(str_replace('/', '_', $fileName));

//check for appropriate characters
if (preg_match('/^[a-zA-Z0-9_-]*$/', $fileName)) {
	//check if file exists
	if (!file_exists($ConfigArray['path'] . $fileName . '.php')) {
		$error = 2;		// route does not exist
		$fileName = $ConfigArray['error'];
	}
} else {
	$error = 1;			// illegal route name
	$fileName = $ConfigArray['error'];
}
require_once $ConfigArray['path'] . $fileName . '.php';
This is more of a Front Includer rather than a Front Controller that dispatches Action Controllers. I think it would probably double the size of the code to support standard /class/method/ style routes that loaded and instantiated a class and called a method.
(#10850)
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: A very simple url manager/rewriter/router

Post by s.dot »

Nice Chris. :)

Today, after i left my computer on for a few days, I went to go browse my website and everything went to the index page. I did a print_r() on $_SERVER and every page was REQUEST_URI = '/'.

Then my browser crashed.

I restarted it and then it started working fine again. Was this just something screwy with my browser, or is request_uri unreliable?
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: A very simple url manager/rewriter/router

Post by Christopher »

s.dot wrote:or is request_uri unreliable?
I don't remember. I know you need to be careful of values in $_SERVER because some come from the user via Apache/webserver without much validation/filtering. Those values cannot be fully trusted, but I don't know if they can get corrupted.
(#10850)
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: A very simple url manager/rewriter/router

Post by s.dot »

Corruption wouldn't matter in this case because it would just send a 404 based on the rewriter script. But as long as REQUEST_URI is always set I'm good. I know the value comes from the server, and has seemed to be set in every instance except this one where the browser crashed.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: A very simple url manager/rewriter/router

Post by Christopher »

The code I posted does an isset() check on the $_SERVER value first. You should probably do that as well.
(#10850)
Post Reply