我遇到了这个问题,主要是关于路径的规范化。 规范化包括以下内容:
- 一个分隔符(我选择支持但永远不会返回反斜杠
\\
)
- 解决间接性:
/../
- 删除重复的分隔符:
/home/www/uploads//file.ext
- 始终删除尾随分隔符。
我编写了一个实现此功能的函数。 我现在无法访问该代码,但自己编写该代码也不难。对于此规范化函数的实现,路径是否为绝对路径并不重要,只需注意前导分隔符即可。
我不太担心操作系统依赖性。 Windows和Linux PHP都理解
/
,因此为简单起见,我始终使用它——但是我猜无论你使用什么分隔符都不重要。
回答您的问题:如果您始终使用
/
并“假定”目录没有尾随分隔符,则路径连接可能非常容易。 “没有尾随分隔符”的假设似乎是一个很好的假设,因为像
dirname
这样的函数会删除尾随分隔符。然后,执行
$dir . "/" . $file
总是安全的。即使结果路径为
/home/uploads/../uploads//my_uploads/myfile.ext
,它仍然可以正常工作。当您需要将路径存储在某处时,规范化变得有用。因为您有了这个规范化函数,您可以做出这些假设。
一个附加的有用函数是创建相对路径的函数。从这两个路径中派生文件的相对路径可能非常有用。
关于
realpath
,我发现它的性能非常低。 如果只调用一次,那还好,但如果在某个循环中使用,性能会受到很大影响。请记住,每次
realpath
调用也是对文件系统的调用。而且,如果传入一些愚蠢的内容,它将简单地返回
false
,我宁愿它抛出异常。对我来说,
realpath
函数是一个很好的“坏函数”的例子,因为它执行两个功能:1. 规范化路径和2. 检查路径是否存在。当然,这两个函数都很有用,但必须分开。它还不区分文件和目录。对于Windows,这通常不是问题,但对于Linux可能会有问题。
我认为在Windows系统上使用realpath("")
会导致一些奇怪的问题。它会返回\\
,这可能是非常不可接受的。
function normalize_path($path) {
$parts = preg_split(":[\\\/]:", $path);
for ($i = 0; $i < count($parts); $i +=1) {
if ($parts[$i] === "..") {
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] === ".") {
unset($parts[$i]);
$parts = array_values($parts);
$i -= 1;
}
if ($i > 0 && $parts[$i] === "") {
unset($parts[$i]);
$parts = array_values($parts);
}
}
return implode("/", $parts);
}
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);
}