替换 PHP 的 realpath()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4049856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace PHP's realpath()
提问by Christian
Apparently, realpath
is very buggy. In PHP 5.3.1, it causes random crashes.
In 5.3.0 and less, realpath
randomly fails and returns false (for the same string of course), plus it always fails on realpath
-ing the same string twice/more (and of course, it works the first time).
显然,realpath
是非常错误的。在 PHP 5.3.1 中,它会导致随机崩溃。在 5.3.0 及更低版本中,realpath
随机失败并返回 false(当然对于相同的字符串),而且它总是在 -realpath
两次/多次使用相同的字符串时失败(当然,它第一次起作用)。
Also, it is so buggy in earlier PHP versions, that it is completely unusable. Well...it already is, since it's not consistent.
此外,它在早期的 PHP 版本中是如此错误,以至于它完全无法使用。嗯......它已经是,因为它不一致。
Anyhow, what options do I have? Maybe rewrite it by myself? Is this advisable?
无论如何,我有哪些选择?也许我自己重写?这是可取的吗?
回答by Christian
Thanks to Sven Arduwie's code (pointed out by Pekka) and some modification, I've built a (hopefully) better implementation:
感谢 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;
}
NB:Unlike PHP's realpath
, this function does not return false on error; it returns a path which is as far as it could to resolving these quirks.
注意:与 PHP 的 不同realpath
,此函数不会在出错时返回 false;它返回一条尽可能解决这些怪癖的路径。
Note 2:Apparently some people can't read properly. Truepath() does not work on network resources including UNC and URLs. It works for the local file system only.
注2:显然有些人无法正确阅读。Truepath() 不适用于包括 UNC 和 URL 在内的网络资源。它仅适用于本地文件系统。
回答by Pavel Perna
here is the modified code that supports UNC paths as well
这是支持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;
}
回答by axiom82
For those Zend users out there, THIS answer may help you, as it did me:
对于那些 Zend 用户,这个答案可能对你有帮助,就像对我一样:
$path = APPLICATION_PATH . "/../directory";
$realpath = new Zend_Filter_RealPath(new Zend_Config(array('exists' => false)));
$realpath = $realpath->filter($path);
回答by Mark Wu
I know this is an old thread, but it is really helpful.
我知道这是一个旧线程,但它确实很有帮助。
I meet a weird Phar::interceptFileFuncsissue when I implemented relative path in phpctags, the realpath()
is really really buggy inside phar.
我遇到一个奇怪的Phar :: interceptFileFuncs问题,当我在执行相对路径phpctags时,realpath()
是真的马车里面药业。
Thanks this thread give me some lights, here comes with my implementation based on christian's implemenation from this thread and this comments.
感谢这个线程给我一些启发,这里是我基于christian's implementation from this thread 和 this comments 的实现。
Hope it works for you.
希望对你有效。
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;
}
回答by Pekka
I have never heard of such massive problems with realpath()
(I always thought that it just interfaces some underlying OS functionality - would be interested in some links), but the User Contributed Notesto the manual page have a number of alternative implementations. Hereis one that looks okay.
我从来没有听说过这么大的问题realpath()
(我一直认为它只是接口一些底层的操作系统功能 - 会对某些链接感兴趣),但是手册页的用户贡献注释有许多替代实现。这是一个看起来不错的。
Of course, it's not guaranteed these implementations take care of all cross-platform quirks and issues, so you'd have to do thorough testing to see whether it suits your needs.
当然,不能保证这些实现会处理所有跨平台的怪癖和问题,因此您必须进行彻底的测试以查看它是否适合您的需求。
As far as I can see though, none of them returns a canonicalized path, they only resolve relative paths. If you need that, I'm not sure whether you can get around realpath()
(except perhaps executing a (system-dependent) console command that gives you the full path.)
但据我所知,它们都没有返回规范化路径,它们只解析相对路径。如果您需要,我不确定您是否可以绕过realpath()
(除了可能执行一个(依赖于系统的)控制台命令为您提供完整路径。)
回答by Andrew Fry
On Windows 7, the code works fine. On Linux, there is a problem in that the path generated starts with (in my case) home/xxx when it should start with /home/xxx ... ie the initial /, indicating the root folder, is missing. The problem is not so much with this function, but with what getcwd returns in Linux.
在 Windows 7 上,代码运行良好。在 Linux 上,存在一个问题,即生成的路径以(在我的情况下)home/xxx 开头,而它应该以 /home/xxx 开头......即初始 /,表示根文件夹,丢失了。问题不在于这个函数,而在于 Linux 中 getcwd 返回的内容。