script.php
$filename = realpath(sprintf("%s/%s", getcwd(), $argv[1]));
var_dump($filename);
Let's try some things
[/foo/bar/bof] $ php script.php ../foo.txt
string(16) "/foo/bar/foo.txt"
[/foo/bar/bof] $ php script.php ../nonexistent.txt
bool(false)
Dammit! realpath
is returning false because the file doesn't exist.
What I'd like to see for the ../nonexistent.txt
is
string(24) "/foo/bar/nonexistent.txt"
How can I get the canonicalized path for any relative path in PHP?
Note: I saw some questions regarding resolving symlink paths. Answers to these questions are not applicable to my question.
This is the best I could come up with
function canonicalize_path($path, $cwd=null) {
// don't prefix absolute paths
if (substr($path, 0, 1) === "/") {
$filename = $path;
}
// prefix relative path with $root
else {
$root = is_null($cwd) ? getcwd() : $cwd;
$filename = sprintf("%s/%s", $root, $path);
}
// get realpath of dirname
$dirname = dirname($filename);
$canonical = realpath($dirname);
// trigger error if $dirname is nonexistent
if ($canonical === false) {
trigger_error(sprintf("Directory `%s' does not exist", $dirname), E_USER_ERROR);
}
// prevent double slash "//" below
if ($canonical === "/") $canonical = null;
// return canonicalized path
return sprintf("%s/%s", $canonical, basename($filename));
}
It requires that all directories in the path exist. The basename
of the path is the only part that can be nonexistent.
An error will be thrown in the event that the dirname doesn't exist.