【问题标题】:How to get canonicalized path (realpath) of nonexistent file in PHP?如何在 PHP 中获取不存在文件的规范化路径(真实路径)?
【发布时间】:2014-06-28 15:09:25
【问题描述】:

script.php

$filename = realpath(sprintf("%s/%s", getcwd(), $argv[1]));
var_dump($filename);

让我们尝试一些事情

[/foo/bar/bof] $ php script.php ../foo.txt
string(16) "/foo/bar/foo.txt"

[/foo/bar/bof] $ php script.php ../nonexistent.txt
bool(false)

该死! realpath 正在返回 false,因为该文件不存在。

我希望看到../nonexistent.txt

string(24) "/foo/bar/nonexistent.txt"

如何获取 PHP 中任何相对路径的规范化路径?

注意:我看到了一些关于解析符号链接路径的问题。这些问题的答案不适用于我的问题。

【问题讨论】:

  • 去掉“坏”文件名,只留下目录组件,然后是 realpath。
  • @MarcB,要处理极端情况,看起来需要更多的工作。请看下面我的回答。我真的希望有更好的方法来做到这一点。

标签: php path canonicalization realpath


【解决方案1】:

这是我能想到的最好的了

function canonicalize_path($path, $cwd=null) {

  // don't prefix absolute paths
  if (substr($path, 0, 1) === "/") {
    $filename = $path;
  }

  // prefix relative path with $root
  else {
    $root      = is_null($cwd) ? getcwd() : $cwd;
    $filename  = sprintf("%s/%s", $root, $path);
  }

  // get realpath of dirname
  $dirname   = dirname($filename);
  $canonical = realpath($dirname);

  // trigger error if $dirname is nonexistent
  if ($canonical === false) {
    trigger_error(sprintf("Directory `%s' does not exist", $dirname), E_USER_ERROR);
  }

  // prevent double slash "//" below
  if ($canonical === "/") $canonical = null;

  // return canonicalized path
  return sprintf("%s/%s", $canonical, basename($filename));
}

它要求路径中的所有目录都存在。路径的basename 是唯一可以不存在的部分。

如果目录名不存在,将引发错误。

【讨论】:

    【解决方案2】:

    我创建了这个:

    $path_canonicalize = function($str, $started = false) use(&$path_canonicalize)
    {
        $str = str_replace('/', DIRECTORY_SEPARATOR, $str).DIRECTORY_SEPARATOR;
    
        if (!$started)
            $str = preg_replace("/".preg_quote(DIRECTORY_SEPARATOR, "'".DIRECTORY_SEPARATOR."'")."{2,}/", DIRECTORY_SEPARATOR, $str);
    
        $pos = strpos($str, '..'.DIRECTORY_SEPARATOR);
        if ($pos !== false)
        {
            $part = trim(substr($str, 0, $pos), DIRECTORY_SEPARATOR);
            $str = $path_canonicalize(trim(substr($part, 0, strrpos($part, DIRECTORY_SEPARATOR)), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.trim(substr($str, $pos+3), DIRECTORY_SEPARATOR), true);
        }
        return rtrim($str, DIRECTORY_SEPARATOR);
    };
    
    /*
    Try those cases to check the consistency:
    $str = __DIR__.'/template//////../header//..';
    $str = __DIR__.'/template///..///../header//..';
    $str = __DIR__.'/template/../header/..';
    $str = __DIR__.'/template/../header/../';
    $str = __DIR__.'/template/../header/..//';
    $str = __DIR__.'/template/../header/..///';
    $str = __DIR__.'/template/../header/..///..';
    $str = __DIR__.'/template/../header/..///../';
    $str = __DIR__.'/template\\..\\header\\..';
    */
    $str = __DIR__.'/template/../header/..///..//';
    echo 'original: '.$str.PHP_EOL;
    echo 'normalized: '.$path_canonicalize($str).PHP_EOL;
    

    一些担忧:

    1. 例程不检查给定路径是相对路径还是绝对路径。
    2. 建议通知绝对路径,但也适用于相对路径。该例程将所有内容视为字符串而不是文件系统。
    3. 最终结果从字符串的开头和结尾删除目录分隔符。
    4. 不支持单点.//.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      相关资源
      最近更新 更多