我碰到这个问题我自己,主要是关于路径正常化。
规范化是:
- 一个分离器(我选择了支持,但永远不会返回向后斜线
\\
)
- 解决间接:
/../
- 删除重复分隔符:
/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,但构建一组新零件非常容易。保存整个索引并进行大量计算。 –