【问题标题】:PHP concatenation of pathsPHP 连接路径
【发布时间】:2011-10-12 02:18:57
【问题描述】:

是否有用于路径连接的 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/”为常用方式?

【问题讨论】:

    标签: php class path relative-path absolute-path


    【解决方案1】:

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

    归一化是:

    • 一个分隔符(我选择支持,但从不返回反斜杠\\
    • 解析间接:/../
    • 删除重复的分隔符:/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 则可能。

    而且我认为在 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 虽然构造一个新的部件数组确实容易得多。保存整个索引和大量计算。
    【解决方案2】:

    realpath 的另一个问题是它不适用于 URL,但连接的逻辑本质上是相同的(两个连接的组件之间应该正好有一个斜线)。显然,以两个斜杠开头的协议部分是该规则的一个例外。但是,将 URL 的各个部分连接在一起的函数还是非常棒的。

    【讨论】:

      【解决方案3】:

      如果路径确实存在,可以使用realpath展开。

      echo realpath("/home/../home/dogbert")
      /home/dogbert
      

      【讨论】:

      • 好的,这很酷,但是有没有办法找出目录分隔符或者有标准化的路径“格式”?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 2016-02-03
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2012-12-31
      相关资源
      最近更新 更多