help with apache rewrite rule

Need help installing PHP, configuring a script, or configuring a server? Then come on in and post your questions! We'll try to help the best we can!

Moderator: General Moderators

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

help with apache rewrite rule

Post by s.dot »

I need help writing a regex for apache .htaccess

I want the path to be passed to index.php?path=$1. I need this not to apply to files ending in .css, .js, .jpg, .gif, .png. Also this doesn't need to apply to index.php.

For example:
domain.tld/Psuedo-Directory-Name/Sub-Name, should be passed to index.php?path=Psuedo-Directory-Name/Sub-Name

I have tried this:
[text]RewriteEngine On
RewriteRule index.php index.php [L]
RewriteRule ^.+ /index.php?path=$1 [L][/text]

I'm sure that's loads wrong and I can do it in one rule.
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
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: help with apache rewrite rule

Post by requinix »

You can use a negative lookahead to make sure the pattern doesn't start with "index.php", then another near the end for the file extensions.

Code: Select all

RewriteRule ^/?(?!index\.php)(.*\.(?!css|js|jpg|gif|png)[^.]+)$ index.php?path=$1 [L]
...if you really want just the one Rule. Otherwise a couple Conds makes it much easier to read.

Code: Select all

RewriteCond %{REQUEST_FILENAME} !\.(css|js|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !=%{DOCUMENT_ROOT}/index.php
RewriteRule ^/?(.*) index.php?path=$1 [L]
Or if you just want index.php to handle anything that doesn't exist,

Code: Select all

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.*) index.php?path=$1 [L]
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: help with apache rewrite rule

Post by s.dot »

That answer is mind boggling. I thank you so much!

I'm making a just-for-fun site that I don't want to put much time into setting it up, but I want pretty urls. So that means I'm not going to use a framework and I'm not going to build my own url loader and not going to use a bunch of rewrites for specific pages.

I'll let index.php handle everything.
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
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: help with apache rewrite rule

Post by s.dot »

So now with the following script I can rewrite
domain.tld/category/pagename to index.php?path=category/pagename
and use category_pagename.php to load the page.

I'll have a single directory with all of the pages.

Code: Select all

if (!empty($_SERVER['REQUEST_URI']))
{
	if ($_SERVER['REQUEST_URI'] == '/' || $_SERVER['REQUEST_URI'] == '/index.php')
	{
		echo 'index';
		//require_once 'index_content.php';
		exit;
	}
	
	if (!empty($_SERVER['REQUEST_URI']))
	{
		//replace beginning and trailing slashes
		$fileName = substr($_SERVER['REQUEST_URI'], 1);
		$fileName = substr($_SERVER['REQUEST_URI'], -1) == '/' ? substr($fileName, 0, strlen($fileName) - 1) : $fileName;
		
		//replace slashes with underscores
		$fileName = strtolower(str_replace('/', '_', $fileName));
		
		if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $fileName . '.php'))
		{
			require_once $_SERVER['DOCUMENT_ROOT'] . '/' . $fileName . '.php';
			exit;
		} else
		{
			echo '404';
			//send 404 header
		}
	}
}
Is there anything wrong with this simplistic approach? It's the first time I've done it.
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
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: help with apache rewrite rule

Post by requinix »

If you're not using the ?path= then the RewriteRules can be simplified a bit. Respectively, and making sure to keep any RewriteConds,

Code: Select all

RewriteRule ^/?(?!index\.php).*\.(?!css|js|jpg|gif|png)[^.]+$ index.php [L]

RewriteRule ^ index.php [L]

RewriteRule ^ index.php [L]
There are a couple comments I can make:
- The REQUEST_URI will always be present so you don't have to worry about that (unless you're using this for CLI scripts too).
- It will include query strings so you need to account for that. I personally like using strtok: it's basically a combination of substr() and strpos() at the same time, even excels if you need to chain a few of those together.

Code: Select all

$path = strtok($_SERVER["REQUEST_URI"], "?");
At the very least make sure that query string doesn't get into the $fileName.
- trim is a really easy way of removing leading and trailing characters. It will remove all of them and not just one from each end, turning "/foo///" into "foo", but that's correct in this case.
- I suggest a strict "only contains letters, numbers, and underscores" check on that filename, just to be extra cautious.

By the way, going to "/index" would trigger index.php and include itself recursively. To be absolutely sure that doesn't happen, I'd include a specific check on $fileName - in case other methods you have in place (ie, the URL rewriting and the ==/index.php check earlier) don't catch the problem beforehand.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: help with apache rewrite rule

Post by s.dot »

All good points. Duh I knew that about trim (face Palm). Yes I gotta remove the query string from possibly being in file name. In some instances though I will want it. Just gotta make sure it's not trying to look for a file named it. I will do a check for numbers, letters, and -and _.

I feel clever for coming up with this very simple method of url management though I bet it's been done a thousand times before, lol.
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
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: help with apache rewrite rule

Post by s.dot »

Yeah, I'm not using the path part so I removed that from the .htacess.

So with the above mentioned points, here's my final little script:

Code: Select all

if (!empty($_SERVER['REQUEST_URI']))
{
	if ($_SERVER['REQUEST_URI'] == '/' || $_SERVER['REQUEST_URI'] == '/index.php' || $_SERVER['REQUEST_URI'] == '/index')
	{
		echo 'index';
		//require_once 'index_content.php';
		exit;
	}
	
	
	//set filename
	$fileName = $_SERVER['REQUEST_URI'];
		
	//replace query string, if any
	if (strpos($fileName, '?') !== false)
	{
		$fileName = preg_replace("#\?.+#", '', $fileName);
	}
		
	//replace beginning and trailing slashes
	$fileName = trim($fileName, '/');
		
	//replace slashes with underscores
	$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.
Post Reply