PHP has a very handy function to convert relative pathnames to absolute paths: realpath(). However, it’s limited in at least two aspects which both make it inconvenient (and sometimes impossible) to use:
After struggling for some time with realpath() I decided to write my own function to expand relative paths to absolute – and here it is :)
/*
RealPath() alternative - converts absolute path into relative.
No license (pubilc domain). Written by Proger_XP, http://proger.i-forge.net/Real_realpath
*/
// path w/o trailing slash unless it's just "/" or "c:/"; converts \ to / removing
// successive / and \; resolves '.' and '..' relative to $cwd.
function Expand($path, $cwd = null) {
$path = self::ExpandLeaveLinks($path, $cwd);
if (function_exists('readlink')) { // prior to PHP 5.3 it only works for *nix.
while (is_link($path) and ($target = readlink($path)) !== false) { $path = $target; }
}
return $path;
}
function ExpandLeaveLinks($path, $cwd = null) {
if (!is_scalar($path) and $path !== null) { return; }
$cwd === null and $cwd = getcwd();
$cwd = static::pathize($cwd);
$path = strtr($path, DS === '\\' ? '/' : '\\', DS);
$firstIsSlash = (isset($path[0]) and strpbrk($path[0], '\\/'));
if ($path === '' or (!$firstIsSlash and isset($path[1]) and $path[1] !== ':')) {
$path = $cwd.DS.$path;
} elseif ($firstIsSlash and isset($cwd[1]) and $cwd[1] === ':') {
// when a drive is specified in CWD then \ or / refers to that drive's root.
$path = substr($cwd, 0, 2).$path;
}
if ($path !== '' and ($path[0] === DS or (isset($path[1]) and $path[1] === ':'))) {
list($prefix, $path) = explode(DS, $path, 2);
$prefix .= DS;
} else {
$prefix = '';
}
$expanded = array();
foreach (explode(DS, $path) as $dir) {
if ($dir === '..') {
array_pop($expanded);
} elseif ($dir !== '' and $dir !== '.') {
$expanded[] = $dir;
}
}
return $prefix.join(DS, $expanded);
}