如何在PHP中join文件系统pathstring?

在PHP中是否有一个内置函数来智能地连接pathstring? 给定“abc / de /”和“/fg/x.php”作为参数的函数应返回“abc / de / fg / x.php”; 使用“abc / de”和“fg / x.php”作为该函数的参数应该给出相同的结果。

如果没有,有没有可用的课程? 分割path或删除其中的一部分也是有价值的。 如果你写了一些东西,你可以在这里分享你的代码吗?

总是使用“/”是可以的,我只为Linux编码。

在Python中有os.path.join() ,这很好。

由于这似乎是一个受欢迎的问题,并填写了“functionbuild议”或“错误报告”…所有此代码段所做的是用斜线连接两个string而不重复斜杠之间。 就这样。 没有更多,不能less。 它不会评估硬盘上的实际path,也不会实际保留起始斜杠(如果需要,请将其添加回来,至less可以确保此代码始终返回一个不带斜杠的string)。

 join('/', array(trim("abc/de/", '/'), trim("/fg/x.php", '/'))); 

最终的结果将始终是一个没有斜线的开始或结束的path,并且内部没有双斜杠。 随意做一个function。

编辑:这是一个很好的灵活的函数包装上面的片段。 您可以根据需要传递尽可能多的path片段,无论是数组还是单独的参数:

 function joinPaths() { $args = func_get_args(); $paths = array(); foreach ($args as $arg) { $paths = array_merge($paths, (array)$arg); } $paths = array_map(create_function('$p', 'return trim($p, "/");'), $paths); $paths = array_filter($paths); return join('/', $paths); } echo joinPaths(array('my/path', 'is', '/an/array')); //or echo joinPaths('my/paths/', '/are/', 'a/r/g/u/m/e/n/t/s/'); 

:O)

 function join_paths() { $paths = array(); foreach (func_get_args() as $arg) { if ($arg !== '') { $paths[] = $arg; } } return preg_replace('#/+#','/',join('/', $paths)); } 

我的解决scheme更简单,更类似于Python os.path.join的工作方式

考虑这些testing用例

 array my version @deceze @david_miller @mark ['',''] '' '' '/' '/' ['','/'] '/' '' '/' '/' ['/','a'] '/a' 'a' '//a' '/a' ['/','/a'] '/a' 'a' '//a' '//a' ['abc','def'] 'abc/def' 'abc/def' 'abc/def' 'abc/def' ['abc','/def'] 'abc/def' 'abc/def' 'abc/def' 'abc//def' ['/abc','def'] '/abc/def' 'abc/def' '/abc/def' '/abc/def' ['','foo.jpg'] 'foo.jpg' 'foo.jpg' '/foo.jpg' '/foo.jpg' ['dir','0','a.jpg'] 'dir/0/a.jpg' 'dir/a.jpg' 'dir/0/a.jpg' 'dir/0/a.txt' 

当尝试join一个以绝对path开头的path,例如joinPaths('/var/www', '/vhosts/site'); @ deceze的函数不会保持前导/ / joinPaths('/var/www', '/vhosts/site');

 function unix_path() { $args = func_get_args(); $paths = array(); foreach($args as $arg) { $paths = array_merge($paths, (array)$arg); } foreach($paths as &$path) { $path = trim($path, '/'); } if (substr($args[0], 0, 1) == '/') { $paths[0] = '/' . $paths[0]; } return join('/', $paths); } 

我的拿:

 function trimds($s) { return rtrim($s,DIRECTORY_SEPARATOR); } function joinpaths() { return implode(DIRECTORY_SEPARATOR, array_map('trimds', func_get_args())); } 

我已经使用了一个匿名函数的trimds ,但旧版本的PHP不支持它。

例:

 join_paths('a','\\b','/c','d/','/e/','f.jpg'); // a\b\c\d\e\f.jpg (on Windows) 

更新 2013年4月 2014年3月

 function join_paths() { return preg_replace('~[/\\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, func_get_args())); } 

这一个将纠正任何斜线匹配您的操作系统,不会删除一个主要的斜线,并清理和连续多个斜线。

另一种方法是使用implode()explode()

 $a = '/a/bc/def/'; $b = '/q/rs/tuv/path.xml'; $path = implode('/',array_filter(explode('/', $a . $b))); echo $path; // -> a/bc/def/q/rs/tuv/path.xml 

获取部分path,你可以使用pathinfo http://nz2.php.net/manual/en/function.pathinfo.php

join来自@deceze的回应看起来不错

攻击这一个不同的方式:

 function joinPaths() { $paths = array_filter(func_get_args()); return preg_replace('#/{2,}#', '/', implode('/', $paths)); } 

这是deceze公布的函数的一个修正版本。 如果没有这个改变,joinPaths('','foo.jpg')会变成'/foo.jpg'

 function joinPaths() { $args = func_get_args(); $paths = array(); foreach ($args as $arg) $paths = array_merge($paths, (array)$arg); $paths2 = array(); foreach ($paths as $i=>$path) { $path = trim($path, '/'); if (strlen($path)) $paths2[]= $path; } $result = join('/', $paths2); // If first element of old path was absolute, make this one absolute also if (strlen($paths[0]) && substr($paths[0], 0, 1) == '/') return '/'.$result; return $result; } 

如果你知道文件/目录存在,你可以添加额外的斜杠(这可能是不必要的),然后调用实时path,即

realpath(join('/', $parts));

这当然不是Python版本,但在很多情况下可能已经足够了。

这似乎是相当好的工作,看起来相当整齐。

 private function JoinPaths() { $slash = DIRECTORY_SEPARATOR; $sections = preg_split( "@[/\\\\]@", implode('/', func_get_args()), null, PREG_SPLIT_NO_EMPTY); return implode($slash, $sections); } 

最好的解决scheme:

 function joinPaths($leftHandSide, $rightHandSide) { return rtrim($leftHandSide, '/') .'/'. ltrim($rightHandSide, '/'); } 

注意:从user89021的评论复制

这是一个像Node的path.resolve一样的path.resolve

 function resolve_path() { $working_dir = getcwd(); foreach(func_get_args() as $p) { if($p === null || $p === '') continue; elseif($p[0] === '/') $working_dir = $p; else $working_dir .= "/$p"; } $working_dir = preg_replace('~/{2,}~','/', $working_dir); if($working_dir === '/') return '/'; $out = []; foreach(explode('/',rtrim($working_dir,'/')) as $p) { if($p === '.') continue; if($p === '..') array_pop($out); else $out[] = $p; } return implode('/',$out); } 

testing用例:

 resolve_path('/foo/bar','./baz') # /foo/bar/baz resolve_path('/foo/bar','/tmp/file/') # /tmp/file resolve_path('/foo/bar','/tmp','file') # /tmp/file resolve_path('/foo//bar/../baz') # /foo/baz resolve_path('/','foo') # /foo resolve_path('/','foo','/') # / resolve_path('wwwroot', 'static_files/png/', '../gif/image.gif') # __DIR__.'/wwwroot/static_files/gif/image.gif' 

从里卡多·加利(Ricardo Galli)的伟大回答可以看出,有些改进是为了避免杀死协议前缀。

这个想法是在一个参数中testing协议的存在,并将其保留在结果中。 警告:这是一个天真的实现!

例如:

 array("http://domain.de","/a","/b/") 

结果(保持协议)

 "http://domain.de/a/b/" 

而不是(杀害协议)

 "http:/domain.de/a/b/" 

但是http://codepad.org/hzpWmpzk需要更好的代码写作技巧。;

我喜欢几个解决scheme。 但是那些把所有'/ +'replace成'/'(正则expression式)的人忘记了python的os.path.join()可以处理这种连接:

 os.path.join('http://example.com/parent/path', 'subdir/file.html') 

结果:' http : //example.com/parent/path/subdir/file.html '