По-видимому, realpath
очень realpath
. В PHP 5.3.1 он вызывает случайные сбои. В 5.3.0 и менее realpath
случайным образом терпит неудачу и возвращает false (для той же строки, конечно), плюс он всегда терпит неудачу на realpath
– одну и ту же строку дважды и более (и, конечно же, она работает в первый раз).
Кроме того, он настолько ошибочен в более ранних версиях PHP, что он полностью непригоден. Ну … это уже так, так как это непротиворечиво.
Во всяком случае, какие у меня варианты? Может быть, переписать его сам? Это целесообразно?
Благодаря коду Свена Ардуви (отмеченному Пеккой ) и некоторой модификации, я построил (надеюсь) лучшую реализацию:
/** * 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: В отличие от realpath
PHP эта функция не возвращает false при ошибке; он возвращает путь, который, насколько это возможно, разрешает эти причуды.
Примечание 2: По-видимому, некоторые люди не могут читать правильно. Truepath () не работает на сетевых ресурсах, включая UNC и URL. Он работает только для локальной файловой системы.
здесь приведен модифицированный код, который также поддерживает пути 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; }
Я никогда не слышал о таких огромных проблемах с realpath()
(я всегда думал, что он просто взаимодействует с некоторыми базовыми функциональными возможностями ОС – будет интересоваться некоторыми ссылками), но пользовательские примечания к странице руководства имеют ряд альтернативных реализаций. Вот один, который выглядит хорошо.
Конечно, это не гарантирует, что эти реализации заботятся обо всех кросс-платформенных причудах и проблемах, поэтому вам придется провести тщательное тестирование, чтобы узнать, подходит ли оно вашим потребностям.
Насколько я вижу, ни один из них не возвращает канонизованный путь, они только разрешают относительные пути. Если вам это нужно, я не уверен, что вы можете обойти realpath()
(за исключением, возможно, выполнения (зависящей от системы) команды консоли, которая дает вам полный путь.)
Я знаю, что это старый поток, но это действительно полезно.
Я встречаю странную проблему Phar :: interceptFileFuncs, когда я реализовал относительный путь в phpctags , realpath()
действительно действительно глючит внутри phar.
Благодаря этой теме дайте мне немного света, здесь идет моя реализация, основанная на реализации христианами этой темы и этих комментариев .
Надеюсь, это сработает для вас.
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; }
Для тех пользователей Zend, этот ответ может помочь вам, так как он сделал меня:
$path = APPLICATION_PATH . "/../directory"; $realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false))); $realpath = $realpath->filter($path);
В Windows 7 код работает нормально. В Linux существует проблема в том, что созданный путь начинается с (в моем случае) home / xxx, когда он должен начинаться с / home / xxx … т.е. отсутствует начальная /, указывающая корневую папку. Проблема заключается не столько в этой функции, сколько в том, что getcwd возвращает в Linux.