LiraNuna's Development Blog
PHP Path resolution class – Relative paths made easy
Posted on Saturday 5 December 2009

Lately I’ve been working on a project that required me to handle a lot of file-system related operations, especially paths.

While PHP offers some basic functions to handle paths, such as basename and dirname to resolute the (direct) parent and base name of a path, it does not offer any means of normalizing or combining a path if it’s on a remote file system that is not in the server’s reach. If the files are local, it offers the function realpath.

I didn’t like the case and decided to write a ‘static’ utility class to handle file paths safely, without worrying about possible path masquerading from broken code.

I hope someone will find the result useful:

 * @class Path
 * @brief Utility class that handles file and directory pathes
 * This class handles basic important operations done to file system paths.
 * It safely renders relative pathes and removes all ambiguity from a relative path.
 * @author Liran Nuna
final class Path
	 * Returns the parent path of this path.
	 * "/path/to/directory" will return "/path/to"
	 * @arg $path	The path to retrieve the parent path from
	public static function dirname($path) {
		return dirname(self::normalize($path));
	 * Returns the last item on the path.
	 * "/path/to/directory" will return "directory"
	 * @arg $path	The path to retrieve the base from
	public static function basename($path) {
		return basename(self::normalize($path));
	 * Normalizes the path for safe usage
	 * This function does several operations to the given path:
	 *   * Removes unnecessary slashes (///path//to/////directory////)
	 *   * Removes current directory references (/path/././to/./directory/./././)
	 *   * Renders relative pathes (/path/from/../to/somewhere/in/../../directory)
	 * @arg $path	The path to normalize
	public static function normalize($path) {
		return array_reduce(explode('/', $path), create_function('$a, $b', '
			if($a === 0)
				$a = "/";
			if($b === "" || $b === ".")
				return $a;
			if($b === "..")
				return dirname($a);
			return preg_replace("/\/+/", "/", "$a/$b");
		'), 0);
	 * Combines a list of pathes to one safe path
	 * @arg $root	The path or array with values to combine into a single path
	 * @arg ...		Relative pathes to root or arrays
	 * @note		This function works with multi-dimentional arrays recursively.
	public static function combine($root, $rel1) {
		$arguments = func_get_args();
		return self::normalize(array_reduce($arguments, create_function('$a,$b', '
				$a = array_reduce($a, "Path::combine");
				$b = array_reduce($b, "Path::combine");
			return "$a/$b";
	 * Empty, private constructor, to prevent instantiation
	private function __construct() {
		// Prevents instantiation

Usage of this class is very simple, Path::basename and Path::dirname perform the same operation as PHP’s native dirname and basename, but safer:

// PHP's native basname will return '..'
echo basename('/path/to/treasure/island/monster/../..') . "\n";
// Safe basename will return 'treasure'
echo Path::basename('/path/to/treasure/island/monster/../..') . "\n";
// PHP's native dirname will return '/path/to/treasure/island/monster/..'
echo dirname('/path/to/treasure/island/monster/../..') . "\n";
// Safe dirname will return '/path/to'
echo Path::dirname('/path/to/treasure/island/monster/../..') . "\n";

Path::normalize will sanitize paths and return the safe real path even if it does not exist on the server:

// Normalize will 'sanitize' this path
// Result: '/path/to/candy/up/ahead/please/go/right'
echo Path::normalize(
	'///../path//to/./monster/././/' .
	'//../candy/.//./up/ahead/.//./' .
	'test//back/../..//please/go///' .
) . "\n";

Lastly, Path::combine will combine paths from variable amount of strings and arrays to form one safe path:

// Combine paths from a relative path and root
// Result: '/var/www/'
echo Path::combine(
) . "\n";
// Combine will also take values from arrays
// Result: '/path/to/directory/sub/TEST/test/lastDirectory/filename.ext'
echo Path::combine(
	), 'sub',
) . "\n";

As always, code I post is under the WTFPL, so you can use it without any obligations.

5 Comments for 'PHP Path resolution class – Relative paths made easy'

    June 21, 2010 | 23:33

    Brilliant….been struggling on an app because of uri resolution issues and this has saved me several hours of additional work :-)

    July 5, 2010 | 2:59

    You saved my day :) — And a few hour’s code…

    Also I like the licence :) This way I can include your code in my public-domain-ish project :).

    December 3, 2010 | 0:13

    You rock. Path resolution was driving me nuts.

    November 28, 2012 | 22:28

    This saved me a lot of time. Thanks.

    And thanks for pointing me to the WTFPL, I’d never come across that before.

    Luca from Italy
    January 10, 2013 | 10:50

    The normalize function is AWESOME!!! You saved my day, many thanks!

Leave a comment



Information for comment users
Line and paragraph breaks are implemented automatically. Your e-mail address is never displayed. Please consider what you're posting.

Use the buttons below to customise your comment.

RSS feed for comments on this post | TrackBack URI