10

显然,realpath是非常错误的。在 PHP 5.3.1 中,它会导致随机崩溃。在 5.3.0 及更低版本中,realpath随机失败并返回 false (当然对于相同的字符串),加上它总是在realpath-ing 相同的字符串两次/更多时失败(当然,它第一次工作)。

此外,它在早期的 PHP 版本中非常有问题,以至于完全无法使用。嗯......它已经是,因为它不一致。

无论如何,我有什么选择?也许自己重写?这是可取的吗?

4

6 回答 6

28

感谢 Sven Arduwie 的代码(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;
}

注意:与 PHP 不同realpath,此函数在错误时不会返回 false;它返回一条尽可能解决这些怪癖的路径。

注2:显然有些人无法正确阅读。Truepath() 不适用于包括 UNC 和 URL 在内的网络资源。它仅适用于本地文件系统。

于 2010-10-29T09:04:26.173 回答
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;
}
于 2015-03-31T15:25:38.823 回答
2

我知道这是一个旧线程,但它确实很有帮助。

当我在phpctags中实现相对路径时,我遇到了一个奇怪的Phar::interceptFileFuncs问题,phar内部真的有很多问题。realpath()

感谢这个线程给了我一些启发,这里有我的实​​现基于基督教的实现从这个线程和这个评论

希望对你有效。

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;
}
于 2013-12-05T08:19:14.280 回答
2

对于那些 Zend 用户,这个答案可能会帮助你,就像我一样:

$path = APPLICATION_PATH . "/../directory";
$realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false)));
$realpath = $realpath->filter($path);
于 2014-05-22T15:59:13.653 回答
1

我从来没有听说过这么大的问题realpath()(我一直认为它只是接口一些底层操作系统功能 - 会对一些链接感兴趣),但是手册页的用户贡献注释有许多替代实现。是一个看起来不错的。

当然,不能保证这些实现会处理所有跨平台的怪癖和问题,因此您必须进行彻底的测试以查看它是否适合您的需求。

但据我所见,它们都没有返回规范化路径,它们只解析相对路径。如果您需要,我不确定您是否可以解决realpath()(除非执行(系统相关的)控制台命令为您提供完整路径。)

于 2010-10-29T07:31:15.777 回答
0

在 Windows 7 上,代码运行良好。在 Linux 上,存在一个问题,即生成的路径以(在我的情况下)home/xxx 开头,而它应该以 /home/xxx 开头......即缺少初始 /,表示根文件夹。问题不在于这个函数,而在于 Linux 中 getcwd 返回的内容。

于 2011-09-06T08:40:12.977 回答