代码之家  ›  专栏  ›  技术社区  ›  Christian

替换PHP的realpath()

  •  9
  • Christian  · 技术社区  · 14 年前

    显然地, realpath 很有车味。在PHP 5.3.1中,它会导致随机崩溃。 在5.3.0及以下版本中, 随机失败并返回false(当然是对于同一字符串),另外它总是在 再分配 -在同一个字符串上重复两次/多次(当然,这是第一次)。

    不管怎样,我有什么选择?也许我自己重写?这是明智的吗?

    6 回复  |  直到 14 年前
        1
  •  27
  •   Community Ian Goodfellow    7 年前

    多亏了斯文·阿杜威的密码( 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;
    }
    

    注: 不像PHP realpath

    注2: 显然有些人不能正确阅读。Truepath()在网络资源(包括UNC和URL)上不起作用。

        2
  •  4
  •   Pavel Perna    9 年前

    下面是支持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;
    }
    
        3
  •  2
  •   axiom82 Joeytje50    10 年前

    $path = APPLICATION_PATH . "/../directory";
    $realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false)));
    $realpath = $realpath->filter($path);
    
        4
  •  1
  •   Pekka    14 年前

    我从没听说过 realpath() (我一直认为它只是接口一些底层操作系统功能-可能会对一些链接感兴趣),但是 User Contributed Notes 到手册页有许多可供选择的实现。 Here

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

    据我所见,它们都不返回规范化的路径,它们只解析相对路径。如果你需要的话,我不确定你是否能出去 realpath()

        5
  •  1
  •   Community Ian Goodfellow    7 年前

    我知道这是一个老线索,但它真的很有帮助。

    Phar::interceptFileFuncs 当我在中实现相对路径时出现问题 phpctags realpath() 是真正的车内法尔。

    谢谢这个线程给我一些提示,下面是我基于 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;
    }
    
        6
  •  0
  •   Andrew Fry    13 年前

    问题不在于这个函数,而在于getcwd在Linux中返回什么。