解析不存在文件的相对路径(如realpath)的最佳方法是什么?

Fra*_*nge 19 php security path

我正在尝试在文件系统抽象中强制执行根目录.我遇到的问题如下:

API允许您读取和写入文件,不仅是本地文件,还包括远程存储文件.因此,各种各样的规范化正在进行中.目前它不支持相对路径,所以这样的事情是不可能的:

$filesystem->write('path/to/some/../relative/file.txt', 'file contents');
Run Code Online (Sandbox Code Playgroud)

我希望能够安全地解析路径,因此输出将是:path/to/relative/file.txt.正如在为此错误/增强(https://github.com/FrenkyNet/Flysystem/issues/36#issuecomment-30319406)创建的github问题中所述,它需要做更多的事情,只需拆分段并删除它们因此.

此外,由于包处理远程文件系统和不存在的文件,realpath是不可能的.

那么,在处理这些路径时应该怎么做呢?

小智 11

引用Jame Zawinski的话:

有些人在面对问题时会想"我知道,我会使用正则表达式".现在他们有两个问题.

protected function getAbsoluteFilename($filename) {
  $path = [];
  foreach(explode('/', $filename) as $part) {
    // ignore parts that have no value
    if (empty($part) || $part === '.') continue;

    if ($part !== '..') {
      // cool, we found a new part
      array_push($path, $part);
    }
    else if (count($path) > 0) {
      // going back up? sure
      array_pop($path);
    } else {
      // now, here we don't like
      throw new \Exception('Climbing above the root is not permitted.');
    }
  }

  // prepend my root directory
  array_unshift($path, $this->getPath());

  return join('/', $path);
}
Run Code Online (Sandbox Code Playgroud)

  • 一些评论: (1) 使用 `empty()` 是危险的,因为它会跳过名称为 `0` 或 `0.0` 的目录。(2) 你应该使用 `DIRECTORY_SEPARATOR` 而不是 `/`。(3) 这也适用于非文件名的任意路径,所以它可能应该被称为`getAbsolutePath`。 (2认同)

Fra*_*nge 6

我已经解决了如何做到这一点,这是我的解决方案:

/**
 * Normalize path
 *
 * @param   string  $path
 * @param   string  $separator
 * @return  string  normalized path
 */
public function normalizePath($path, $separator = '\\/')
{
    // Remove any kind of funky unicode whitespace
    $normalized = preg_replace('#\p{C}+|^\./#u', '', $path);

    // Path remove self referring paths ("/./").
    $normalized = preg_replace('#/\.(?=/)|^\./|\./$#', '', $normalized);

    // Regex for resolving relative paths
    $regex = '#\/*[^/\.]+/\.\.#Uu';

    while (preg_match($regex, $normalized)) {
        $normalized = preg_replace($regex, '', $normalized);
    }

    if (preg_match('#/\.{2}|\.{2}/#', $normalized)) {
        throw new LogicException('Path is outside of the defined root, path: [' . $path . '], resolved: [' . $normalized . ']');
    }

    return trim($normalized, $separator);
}
Run Code Online (Sandbox Code Playgroud)