Is there a PHP internal function for path concatenation ? What possibilities do I have to merge several paths (absolute and relative).
//Example:
$path1="/usr/home/username/www";
$path2="domainname";
$path3="images/thumbnails";
$domain="exampledomain.com";
//As example: Now I want to create a new path (domain + path3) on the fly.
$result = $domain.DIRECTORY_SEPARATOR.$path3
Ok, there is an easy solution for this example, but what if there are different dictionary separators or some paths are a little bit more complicated?
Is there an existing solution for trim it like this: /home/uploads/../uploads/tmp => /home/uploads/tmp ....
And how would a platform-independent version of an path-concat-function look like?
should an relative path start with "./" as prefix or is "home/path/img/" the common way?
I ran into this problem myself, primarily regarding the normalization of paths.
Normalization is:
\\
)/../
/home/www/uploads//file.ext
I've written a function that achieves this. I don't have access to that code right now, but it's also not that hard to write it yourself.
Whether a path is absolute or not doesn't really matter for the implementation of this normalization function, just watch out for the leading separator and you're good.
I'm not too worried about OS dependence. Both Windows and Linux PHP understand /
so for the sake of simplicity I'm just always using that - but I guess it doesn't really matter what separator you use.
To answer your question: path concatenation can be very easy if you just always use /
and assume that a directory has no trailing separator. 'no trailing separator' seems like a good assumption because functions like dirname
remove the trailing separator.
Then it's always safe to do: $dir . "/" . $file
.
And even if the result path is /home/uploads/../uploads//my_uploads/myfile.ext
it's still going to work fine.
Normalization becomes useful when you need to store the path somewhere. And because you have this normalization function you can make these assumptions.
An additional useful function is a function to make relative paths.
It can be useful to derive from those two paths, what the relative path to the file is.
realpath
I've found realpath
to be extremely performance heavy. It's not so bad if you're calling it once but if you're doing it in a loop somewhere you get a pretty big hit. Keep in mind that each realpath
call is a call to the filesystem as well. Also, it will simply return false
if you pass in something silly, I'd rather have it throw an Exception.
To me the realpath
function is a good example of a BAD function because it does two things: 1. It normalizes the path and 2. it checks if the path exists. Both of these functions are useful of course but they must be separated. It also doesn't distinguish between files and directories. For windows this typically isn't a problem, but for Linux it can be.
And I think there is some quirky-ness when using realpath("")
on Windows. I think it will return \\
- which can be profoundly unacceptable.
/**
* This function is a proper replacement for realpath
* It will _only_ normalize the path and resolve indirections (.. and .)
* Normalization includes:
* - directiory separator is always /
* - there is never a trailing directory separator
* @param $path
* @return String
*/
function normalize_path($path) {
$parts = preg_split(":[\\\/]:", $path); // split on known directory separators
// resolve relative paths
for ($i = 0; $i < count($parts); $i +=1) {
if ($parts[$i] === "..") { // resolve ..
if ($i === 0) {
throw new Exception("Cannot resolve path, path seems invalid: `" . $path . "`");
}
unset($parts[$i - 1]);
unset($parts[$i]);
$parts = array_values($parts);
$i -= 2;
} else if ($parts[$i] === ".") { // resolve .
unset($parts[$i]);
$parts = array_values($parts);
$i -= 1;
}
if ($i > 0 && $parts[$i] === "") { // remove empty parts
unset($parts[$i]);
$parts = array_values($parts);
}
}
return implode("/", $parts);
}
/**
* Removes base path from longer path. The resulting path will never contain a leading directory separator
* Base path must occur in longer path
* Paths will be normalized
* @throws Exception
* @param $base_path
* @param $longer_path
* @return string normalized relative path
*/
function make_relative_path($base_path, $longer_path) {
$base_path = normalize_path($base_path);
$longer_path = normalize_path($longer_path);
if (0 !== strpos($longer_path, $base_path)) {
throw new Exception("Can not make relative path, base path does not occur at 0 in longer path: `" . $base_path . "`, `" . $longer_path . "`");
}
return substr($longer_path, strlen($base_path) + 1);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With