john.mcclumpha

php : A solution to absolute and relative paths in PHP

Published: 3 months ago

When coding a dynamic site, there's often times where using relative paths is not as simple as it should be, especially when using things such as mod_rewrites to change the paths used within a URL. As a result things can often "fall to pieces".

If an html file exists in the root directory of a site and the image files are in a folder called images, the following img tag is the sort of thing often used (albeit without height, width, alt, title, etc. attributes):

<img src="images/logo.jpg" />

As long as the referencing file is located in the root path of the site then this will work without a hitch - the problem occurs when a file doesn't exist in the root (or the URL used to access the file doesn't use the root path).

example: A file exists within a directory called articles, this may be accessed as: http://www.example.com/articles/test.html

The img tag now looks like the following:

<img src="../images/logo.jpg" />

So far there's no major hiccups as we're (theoretically) dealing with static html files which require painful editing on an individual basis to function. Let's introduce some dynamics to the structure of the site and its content.

First we'll make the image tag part of a common header file which is included from within each page on the site (/includes/static/header.php). The problem we now have is that if the page in the root directory (/index.php) is including this file then the path to the logo is images/logo.jpg, whilst if the article page (/articles/test.php) is including it the path is ../images/logo.jpg

About now, you may be thinking "why don't I use absolute paths?" - the answer of course is portability.

If the path was changed to /images/logo.jpg then it would certainly work with the examples cited above, however when the site is moved (for whatever reason) and the root of the site is no longer the root of the host (http://www.example.com) things fall apart.

The solution is to have a dynamic absolute path. OK so it's an oxymoron of sorts, but read on...

One habit I have used for quite some time now is to include an "initialization file" from every page within a dynamic site. The purpose of which is to define some variables which will be used throughout and make life much easier. The path to include this is always a relative path, but it's (potentially) the last time you'll ever need to use one. Let's assume the file is called siteini.php and exists in the root folder of the site. From your /index.php you could include this with:

include("siteini.php");

whilst from your /articles/test.php it would be:

include("../siteini.php");

Now back to our path solution, there are two paths I set in this initialization file. The first is the path to the root of the website from a client perspective (usually "/") whilst the other is the path to the root of the website from a server perspective (something like: "/var/www/" for linux servers). So the siteini.php file might look like:

$clientRoot = "/';
$serverRoot = "/var/www/";

So how do we use that for our image tag? within the included header file (make sure it's a php file) change the tag as follows:

<img src="<? echo $clientRoot; ?>images/logo.jpg" />

All of a sudden things are much more portable with these variables being set in the one file.

But why the server side root variable?

To include the header file which contains the image tag we need to reference things from a server perspective so we would include it as:

include($serverRoot . "/includes/static/header.php");

Of course some would say that declaring variables in such a way is leaning toward a procedural approach to coding, so if you prefer you can make an object to hold them all:

$siteini->clientRoot = "/";
$siteini->serverRoot = "/var/www/";

Another great use for this is when you have both live and development versions of a site. You can modify the values contained within these paths based upon the hostname being used to access the site:

switch($_SERVER['HTTP_HOST']) {

	case "www.example.com":
		$clientRoot = "/";
		$serverRoot = "/var/www/";
		break;

	case "development.local":
		$clientRoot = "/sites/example/";
		$serverRoot = "/var/www/sites/example/";
		break;
		
	default:
		die("Root paths not defined");

}

Hopefully this will be of some use to you - it's actually part of my modular codebase which I'm planning on releasing to the public later this year - so keep your eyes peeled.

recent posts

Have you checked out Mister Wong? Simply the best way to manage your bookmarks online:
Mister Wong