PHP串联路径

NaN*_*NaN 4 php class path relative-path absolute-path

是否有用于路径连接的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
Run Code Online (Sandbox Code Playgroud)

好的,这个例子有一个简单的解决方案,但是如果有不同的字典分隔符或某些路径有点复杂呢?

是否有现成的解决方案,如下所示:/home/uploads/../uploads/tmp =>/home/uploads/tmp ....

并行平台函数的平台无关版本如何?

相对路径应该以"./"作为前缀开头,还是"home/path/img /"常用方式?

Dog*_*ert 6

如果该路径确实存在,您可以使用realpath它来扩展它。

echo realpath("/home/../home/dogbert")
/home/dogbert
Run Code Online (Sandbox Code Playgroud)


Hal*_*yon 5

我自己遇到了这个问题,主要是关于路径的规范化.

规范化是:

  • 一个分隔符(我选择支持,但永远不会返回斜杠\\)
  • 解决间接问题: /../
  • 删除重复的分隔符: /home/www/uploads//file.ext
  • 始终删除尾随分隔符.

我写了一个功能来实现这个目标.我现在无权访问该代码,但自己编写代码并不困难.

路径是否绝对对于这个规范化函数的实现并不重要,只需要注意领先的分隔符并且你很好.

我不太担心操作系统的依赖性.Windows和Linux PHP都理解/为了简单起见我总是使用它 - 但我想你使用什么分隔符并不重要.


回答你的问题:如果你总是使用/假设一个目录没有尾随分隔符,那么路径连接可以非常简单.'没有尾随分隔符'似乎是一个很好的假设,因为dirname删除尾随分隔符等功能.

然后它总是安全的:$dir . "/" . $file.

即使结果路径/home/uploads/../uploads//my_uploads/myfile.ext仍然可以正常工作.

当您需要在某处存储路径时,规范化变得很有用.而且因为你有这个规范化功能,你可以做出这些假设.


另一个有用的功能是制作相对路径的功能.

  • /文件/上传
  • /files/uploads/my_uploads/myfile.ext

从这两个路径派生,文件的相对路径是什么是有用的.


真实路径

我发现realpath性能非常重.如果你一次调用它就不是那么糟糕,但是如果你在一个循环中这样做你会受到很大影响.请记住,每次realpath调用都是对文件系统的调用.而且,false如果你传入一些愚蠢的东西,它会简单地返回,我宁愿让它抛出异常.

对我来说,该realpath函数是BAD函数的一个很好的例子,因为它做了两件事:1.规范路径和2.它检查路径是否存在.这些功能当然都很有用,但它们必须分开.它也不区分文件和目录.对于Windows,这通常不是问题,但对于Linux它可以.

我认为realpath("")在Windows上使用时有一些奇怪之处.我认为它会回归\\- 这可能是非常不可接受的.


/**
 * 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);
}
Run Code Online (Sandbox Code Playgroud)