PHP连接路径

4
有没有PHP内部函数可以进行路径拼接?我有哪些选项来合并多个路径(绝对路径和相对路径)?
//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

好的,对于这个例子有一种简单的解决方法,但如果有不同的字典分隔符或某些路径有点复杂,怎么办?

是否存在将其修剪为这样的现成解决方案:/home/uploads/../uploads/tmp => /home/uploads/tmp ....

一个跨平台版本的路径连接函数会是什么样子呢?

相对路径是否应该以"./"作为前缀,或者"home/path/img/"是通用方式?

3个回答

6
如果路径实际存在,你可以使用realpath来扩展它。
echo realpath("/home/../home/dogbert")
/home/dogbert

好的,这很酷,但有没有一种方法可以找出目录分隔符或者是否有标准化的路径“格式”? - NaN

5
我遇到了这个问题,主要是关于路径的规范化。 规范化包括以下内容:
- 一个分隔符(我选择支持但永远不会返回反斜杠\\) - 解决间接性:/../ - 删除重复的分隔符:/home/www/uploads//file.ext - 始终删除尾随分隔符。
我编写了一个实现此功能的函数。 我现在无法访问该代码,但自己编写该代码也不难。对于此规范化函数的实现,路径是否为绝对路径并不重要,只需注意前导分隔符即可。
我不太担心操作系统依赖性。 Windows和Linux PHP都理解/,因此为简单起见,我始终使用它——但是我猜无论你使用什么分隔符都不重要。
回答您的问题:如果您始终使用/并“假定”目录没有尾随分隔符,则路径连接可能非常容易。 “没有尾随分隔符”的假设似乎是一个很好的假设,因为像dirname这样的函数会删除尾随分隔符。然后,执行$dir . "/" . $file总是安全的。即使结果路径为/home/uploads/../uploads//my_uploads/myfile.ext,它仍然可以正常工作。当您需要将路径存储在某处时,规范化变得有用。因为您有了这个规范化函数,您可以做出这些假设。
一个附加的有用函数是创建相对路径的函数。从这两个路径中派生文件的相对路径可能非常有用。
关于realpath,我发现它的性能非常低。 如果只调用一次,那还好,但如果在某个循环中使用,性能会受到很大影响。请记住,每次realpath调用也是对文件系统的调用。而且,如果传入一些愚蠢的内容,它将简单地返回false,我宁愿它抛出异常。对我来说,realpath函数是一个很好的“坏函数”的例子,因为它执行两个功能:1. 规范化路径和2. 检查路径是否存在。当然,这两个函数都很有用,但必须分开。它还不区分文件和目录。对于Windows,这通常不是问题,但对于Linux可能会有问题。

我认为在Windows系统上使用realpath("")会导致一些奇怪的问题。它会返回\\,这可能是非常不可接受的。


/**
 * 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);
}

虽然构建一个新的零件数组会更容易,但是+1能够节省整个索引和大量计算。 - Tim-Erwin

0
另一个 realpath 的问题是它不能处理 URL,然而连接的逻辑基本上是相同的(两个连接的组件之间应该有且只有一个斜杠)。显然,以两个斜杠开头的协议部分是这个规则的例外。但是,一个能够将 URL 的各个部分连接在一起的函数会非常方便。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接