Заменить реальный путь PHP () - PullRequest
9 голосов
/ 29 октября 2010

Видимо, realpath очень глючит.В PHP 5.3.1 это вызывает случайные сбои.В версии 5.3.0 и менее realpath случайным образом завершается с ошибкой и возвращает false (для одной и той же строки, разумеется), плюс всегда происходит сбой при realpath - при одной и той же строке дважды / более (и, конечно, это работает в первый раз).

Кроме того, в более ранних версиях PHP он настолько глючит, что его совершенно невозможно использовать.Ну ... это уже так, поскольку это не соответствует.

В любом случае, какие у меня есть варианты?Может быть, переписать это сам?Желательно ли это?

Ответы [ 6 ]

27 голосов
/ 29 октября 2010

Благодаря коду Свена Ардуви ( указан Пеккой ) и некоторой модификации, я построил (надеюсь) лучшую реализацию:

/**
 * 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. Работает только для локальной файловой системы.

4 голосов
/ 31 марта 2015

вот модифицированный код, который также поддерживает пути 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 голосов
/ 22 мая 2014

Для тех пользователей Zend, ЭТОТ ответ может помочь вам, как и мне:

$path = APPLICATION_PATH . "/../directory";
$realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false)));
$realpath = $realpath->filter($path);
1 голос
/ 05 декабря 2013

Я знаю, что это старая ветка, но она действительно полезна.

Я сталкиваюсь со странной Phar :: interceptFileFuncs , когда я реализовал относительный путь в phpctags , realpath() действительно глючит внутри phar.

Спасибо, этот поток дал мне немного света, здесь идет моя реализация, основанная на реализации christian из этой темы и этого комментариев .

Надеюсь, у вас это получится.

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;
}
1 голос
/ 29 октября 2010

Я никогда не слышал о таких огромных проблемах с realpath() (я всегда думал, что он просто сопрягает некоторые базовые функциональные возможности ОС - было бы интересно узнать о некоторых ссылках), но Пользовательские комментарии к руководству страница имеет ряд альтернативных реализаций. Здесь это тот, который выглядит хорошо.

Конечно, не гарантируется, что эти реализации позаботятся обо всех кросс-платформенных причудах и проблемах, поэтому вам придется провести тщательное тестирование, чтобы убедиться, что оно соответствует вашим потребностям.

Насколько я вижу, ни один из них не возвращает канонизированный путь, они разрешают только относительные пути. Если вам это нужно, я не уверен, сможете ли вы обойти realpath() (за исключением, возможно, выполнения (системно-зависимой) консольной команды, которая дает вам полный путь.)

0 голосов
/ 06 сентября 2011

В Windows 7 код работает нормально. В Linux существует проблема в том, что сгенерированный путь начинается с (в моем случае) home / xxx, когда он должен начинаться с / home / xxx ... т.е. начальный /, указывающий на корневую папку, отсутствует. Проблема не столько в этой функции, сколько в том, что getcwd возвращает в Linux.

...