显然,realpath
非常错误。在PHP 5.3.1中,它会导致随机崩溃。
在5.3.0及更低版本中,realpath
随机失败并返回false(对于相同的字符串),加上它始终在realpath
上失败 - 相同的字符串两次/更多(当然,它第一次工作。)
此外,在早期的PHP版本中,它是如此的错误,它完全无法使用。嗯......它已经存在,因为它不一致。
无论如何,我有什么选择?也许自己重写一下?这是可取的吗?
答案 0 :(得分:27)
感谢Sven Arduwie的代码(pointed out by Pekka)和一些修改,我已经建立了一个(希望)更好的实现:
/**
* This function is to replace PHP's extremely buggy realpath().
* @param string The original path, can be relative etc.
* @return string The resolved path, it might not exist.
*/
function truepath($path){
// whether $path is unix or not
$unipath=strlen($path)==0 || $path{0}!='/';
// attempts to detect if path is relative in which case, add cwd
if(strpos($path,':')===false && $unipath)
$path=getcwd().DIRECTORY_SEPARATOR.$path;
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part) continue;
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
$path=implode(DIRECTORY_SEPARATOR, $absolutes);
// resolve any symlinks
if(file_exists($path) && linkinfo($path)>0)$path=readlink($path);
// put initial separator that could have been lost
$path=!$unipath ? '/'.$path : $path;
return $path;
}
NB:与PHP的realpath
不同,此函数在出错时不返回false;它返回一条路径,尽可能地解决这些怪癖。
注2:显然有些人无法正常阅读。 Truepath()不适用于包括UNC和URL在内的网络资源。 仅适用于本地文件系统。
答案 1 :(得分:4)
这里是支持UNC路径的修改代码
static public function truepath($path)
{
// whether $path is unix or not
$unipath = strlen($path)==0 || $path{0}!='/';
$unc = substr($path,0,2)=='\\\\'?true:false;
// attempts to detect if path is relative in which case, add cwd
if(strpos($path,':') === false && $unipath && !$unc){
$path=getcwd().DIRECTORY_SEPARATOR.$path;
if($path{0}=='/'){
$unipath = false;
}
}
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part){
continue;
}
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
$path = implode(DIRECTORY_SEPARATOR, $absolutes);
// resolve any symlinks
if( function_exists('readlink') && file_exists($path) && linkinfo($path)>0 ){
$path = readlink($path);
}
// put initial separator that could have been lost
$path = !$unipath ? '/'.$path : $path;
$path = $unc ? '\\\\'.$path : $path;
return $path;
}
答案 2 :(得分:2)
对于那些Zend用户来说,这个答案可能对你有帮助,就像我一样:
$path = APPLICATION_PATH . "/../directory";
$realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false)));
$realpath = $realpath->filter($path);
答案 3 :(得分:1)
我从来没有听说过realpath()
这样的大问题(我一直认为它只是接口一些底层操作系统功能 - 会对某些链接感兴趣),但手册页的User Contributed Notes有许多替代实施。 Here是一个看起来不错的。
当然,并不能保证这些实现能够解决所有跨平台的怪癖和问题,因此您必须进行全面测试才能确定它是否符合您的需求。
据我所知,没有一个返回规范化路径,它们只解析相对路径。如果你需要,我不确定你是否可以绕过realpath()
(除了可能执行一个(系统相关的)控制台命令,它给你一个完整的路径。)
答案 4 :(得分:1)
我知道这是一个旧线程,但它确实很有帮助。
当我在Phar::interceptFileFuncs中实现相对路径时遇到了一个奇怪的phpctags问题,realpath()
在phar中确实非常错误。
感谢这个帖子给我一些启示,这里有我的实现,基于christian从这个线程和comments的实现。
希望它适合你。
function relativePath($from, $to)
{
$fromPath = absolutePath($from);
$toPath = absolutePath($to);
$fromPathParts = explode(DIRECTORY_SEPARATOR, rtrim($fromPath, DIRECTORY_SEPARATOR));
$toPathParts = explode(DIRECTORY_SEPARATOR, rtrim($toPath, DIRECTORY_SEPARATOR));
while(count($fromPathParts) && count($toPathParts) && ($fromPathParts[0] == $toPathParts[0]))
{
array_shift($fromPathParts);
array_shift($toPathParts);
}
return str_pad("", count($fromPathParts)*3, '..'.DIRECTORY_SEPARATOR).implode(DIRECTORY_SEPARATOR, $toPathParts);
}
function absolutePath($path)
{
$isEmptyPath = (strlen($path) == 0);
$isRelativePath = ($path{0} != '/');
$isWindowsPath = !(strpos($path, ':') === false);
if (($isEmptyPath || $isRelativePath) && !$isWindowsPath)
$path= getcwd().DIRECTORY_SEPARATOR.$path;
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$pathParts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutePathParts = array();
foreach ($pathParts as $part) {
if ($part == '.')
continue;
if ($part == '..') {
array_pop($absolutePathParts);
} else {
$absolutePathParts[] = $part;
}
}
$path = implode(DIRECTORY_SEPARATOR, $absolutePathParts);
// resolve any symlinks
if (file_exists($path) && linkinfo($path)>0)
$path = readlink($path);
// put initial separator that could have been lost
$path= (!$isWindowsPath ? '/'.$path : $path);
return $path;
}
答案 5 :(得分:0)
在Windows 7上,代码运行正常。在Linux上,存在一个问题,即生成的路径以(在我的情况下)home / xxx开始时应该以/ home / xxx开头...即缺少初始/,表示根文件夹。 问题不在于这个函数,而是在Linux中返回getcwd。