note 82667 deleted from function.realpath by danbrown

From: Date: Mon, 01 Jun 2009 12:58:28 +0000
Subject: note 82667 deleted from function.realpath by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-156223@lists.php.net to get a copy of this message
Note Submitter: heavyraptor at gmail dot com ---- Looks like a lot of people are looking for an 'unrealpath' or 'relative-path' function, returning the relative path from a directory to another one (in most cases ./). Unfortunately it's kinda difficult to program such a function which really works correctly, with any type of path. Most of the posted functions have some little bugs. I compared the following functions: - unrealpath() by Zach Bernal zbernal at ucsc dot edu (http://ch2.php.net/manual/en/function.realpath.php#78567) - UnRealPath() by alban dot lopez+php dot net at gmail dot com (http://ch2.php.net/manual/en/function.realpath.php#77968) - rel_path() by Santosh Patnaik (http://ch2.php.net/manual/en/function.realpath.php#77203) The file I used for testing is located at /var/www/test/test.php. unrealpath(../test/test.php) -> ../test/test.php UnRealPath(../test/test.php) -> ./var/www/test/test.php rel_path(../test/test.php) -> ./../../../../../test/test.php should actually return: ./test.php UnRealPath(./) -> ./var/www/test/ rel_path(./): -> ./../../../../. should actually return: ./ Exapmple on windows: the file I used for testing is located at C:/www/test/test.php. unrealpath(C:/www/test/../) -> C:/www/test/../ UnRealPath(C:/www/test/../) -> . rel_path(C:/www/test/../) -> ./../../../../C:/www/test/../ should actually return: ../ So here's my try, I use 3 functions to get the relative path between two directories: - clean_path() -> replace / or \ with the correct directory separator etc. - absolute_path() -> get absolute path of the given path (actually the same as realpath(), but using clean_path() to f.e. add a directory separator at the end if the path isn't a file) - relative_path() -> get relative path from one to another path <?php define('DIR_DELIM',DIRECTORY_SEPARATOR); // in case you'd like to change it. Easier to define a constant instead of including a parameter in each function for the directory separator function clean_path($path) { $path = str_replace(array('/','\\'),DIR_DELIM,$path); $path = preg_replace('/[' . preg_quote(DIR_DELIM,DIR_DELIM) . ']{2,}/',DIR_DELIM,$path); return substr($path,-1) != DIR_DELIM ? $path . DIR_DELIM : $path; } function absolute_path($path) { $filename = ''; if (is_file($path)) { $filename = basename($path); $path = dirname($path); } return clean_path(realpath($path)) . $filename; } function relative_path($path,$source = null) { $filename = ''; if (is_file($path)) { $filename = basename($path); $path = dirname($path); } $path = absolute_path($path); $source = absolute_path(is_null($source) ? '.' : $source); if ($path == $source) return '.' . DIR_DELIM . $filename; $path_dirs = explode(DIR_DELIM,substr($path,0,-1)); $source_dirs = explode(DIR_DELIM,substr($source,0,-1)); for ($i = 0; $i < min(count($path_dirs),count($source_dirs)); $i++) if ($path_dirs[$i] != $source_dirs[$i]) break; if ($i == 0) return false; $relative_path = str_repeat('..' . DIR_DELIM,count($source_dirs) - $i); $same_path = implode(DIR_DELIM,array_splice($path_dirs,0,$i)); if ($same_path != '' && strpos($path,$same_path) === 0) $path = substr($path,strlen($same_path) + 1); return $relative_path . ($path == DIR_DELIM ? '' : $path) . $filename; } ?> Of course my functions might have some bugs too, but I tested it with a lot of different paths and it seems to work with all of them, I think ;). I tried my best. Please note that both directories ($path and $source) need to exist, otherwise the function won't return a correct path. If you ignore $source (in most cases I suppose) then the actual directory ./ is taken as $source. Testing: relative_path(/var/www/) -> ../ relative_path(/var/www/../test/../../) -> ../../../ relative_path(../) -> ../ relative_path(/) -> ../../../ relative_path(../test/test.php) -> ./test.php I did a lot of testings on windows too (path like C:/www/ etc.) and it worked with all the paths I used. I know my english isn't too good, but I hope you understood what I wanted to say ... Have fun

« previous php.notes (#156223) next »