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

问题描述:

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

I'm trying to enforce a root directory in a filesystem abstraction. The problem I'm encountering is the following:

API使您不仅可以读写文件,还可以读写本地文件,也可以读写远程文件.因此,在引擎盖下进行了各种标准化.目前,它不支持相对路径,所以这样的事情是不可能的:

The API lets you read and write files, not only to local but also remote storages. So there's all kinds of normalisation going on under the hood. At the moment it doesn't support relative paths, so something like this isn't possible:

$filesystem->write('path/to/some/../relative/file.txt', 'file contents');

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

I want to be able to securely resolve the path so the output is would be: path/to/relative/file.txt. As is stated in a github issue which was created for this bug/enhancement (https://github.com/FrenkyNet/Flysystem/issues/36#issuecomment-30319406) , it needs to do more that just splitting up segments and removing them accordingly.

此外,由于该软件包可以处理远程文件系统和不存在的文件,因此realpath也不可能.

Also, since the package handles remote filesystems and non-existing files, realpath is out of the question.

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

So, how should one go about when dealing with these paths?

我已经解决了此问题,这是我的解决方案:

I've resolved how to do this, this is my solution:

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