Как присоединиться к строкам пути файловой системы в PHP?
есть ли встроенная функция в PHP для интеллектуального соединения строк пути? Функция, заданная "abc / de /" и "/fg/x.php " как аргументы, должны вернуться "abc/de/fg/x.php"; тот же результат должен быть получен с использованием "abc / de" и "fg/x.php-в качестве аргументов для этой функции.
если нет, то есть ли доступный класс? Это также может быть полезно для разделения путей или удаления их частей. Если вы что-то написали, можете поделиться своим кодом здесь?
Это нормально, чтобы всегда использовать "/", Я кодирую только для Linux.
в Python есть os.path.join(), что здорово.
15 ответов:
поскольку это, кажется, популярный вопрос, и комментарии заполняются "предложениями функций" или "отчетами об ошибках"... Все, что делает этот фрагмент кода, - это соединяет две строки с косой чертой, не дублируя косые черты между ними. Вот и все. Ни больше, ни меньше. Он не оценивает фактические пути на жестком диске и фактически не сохраняет начальную косую черту (добавьте это обратно, если это необходимо, по крайней мере, вы можете быть уверены, что этот код всегда возвращает строку без начиная разрез.)
join('/', array(trim("abc/de/", '/'), trim("/fg/x.php", '/')));конечным результатом всегда будет путь без косых черт в начале или конце и без двойных косых черт внутри. Не стесняйтесь сделать из этого функцию.
изменить: Вот хорошая гибкая функциональная оболочка для приведенного выше фрагмента. Вы можете передать столько фрагментов пути, сколько хотите, либо в виде массива, либо в виде отдельных аргументов:
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)); }мое решение проще и больше похоже на способ Python os.путь.присоединяйтесь к работам
рассмотрим эти тесты
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'
функция @ deceze не сохраняет ведущий / при попытке присоединиться к пути, который начинается с абсолютного пути Unix, например
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 годамарт 2014мая 2018:function join_paths(...$paths) { return preg_replace('~[/\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, $paths)); }этот будет исправлять любые косые черты в соответствии с вашей ОС, не будет удалять ведущую косую черту и очищать и несколько косых черт подряд.
альтернативой является использование
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
Если вы знаете, что файл/каталог не существует, вы можете добавить дополнительные косые черты (которые могут быть ненужными), а затем позвонить realpath, т. е.
realpath(join('/', $parts));Это, конечно, не совсем то же самое, что Python версии, но во многих случаях может быть достаточно хорошим.
для получения части путей, которые вы можете использовать pathinfo http://nz2.php.net/manual/en/function.pathinfo.php
для присоединения к ответу от @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; }
Это, кажется, работает довольно хорошо, и выглядит достаточно аккуратно для меня.
private function JoinPaths() { $slash = DIRECTORY_SEPARATOR; $sections = preg_split( "@[/\\]@", implode('/', func_get_args()), null, PREG_SPLIT_NO_EMPTY); return implode($slash, $sections); }
лучшее решение нашел:
function joinPaths($leftHandSide, $rightHandSide) { return rtrim($leftHandSide, '/') .'/'. ltrim($rightHandSide, '/'); }Примечание: скопировано из комментария user89021
Решение ниже использует логику, предложенную @RiccardoGalli, но улучшается, чтобы воспользоваться
DIRECTORY_SEPARATORконстанта, как предположили @Qix и @FélixSaparelli, и, что более важно, к обрезать каждый данный элемент чтобы избежать пробелов-только имена папок, появляющиеся в конечном пути (это было требование в моем случае).относительно побега разделителя каталогов внутри
preg_replace()шаблон, как вы можете видеть, я использовалpreg_quote()функция, которая выполняет эту работу штраф.
Кроме того, я бы заменил mutiple сепараторы только (регулярное выражение Квантор{2,}).// PHP 7.+ function paths_join(string ...$parts): string { $parts = array_map('trim', $parts); $path = []; foreach ($parts as $part) { if ($part !== '') { $path[] = $part; } } $path = implode(DIRECTORY_SEPARATOR, $path); return preg_replace( '#' . preg_quote(DIRECTORY_SEPARATOR) . '{2,}#', DIRECTORY_SEPARATOR, $path ); }
вот функция, которая ведет себя как узла!--2-->:
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); }тестовые случаи:
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'
из Великого ответа Рикардо Галли, немного улучшения, чтобы избежать убийства префикса протокола.
идея состоит в том, чтобы проверить наличие протокола в одном аргументе и сохранить его в результате. Предупреждение: это наивная реализация!
например:
array("http://domain.de","/a","/b/")результатов (ведение протокола)
"http://domain.de/a/b/"вместо (протокол убийства)
"http:/domain.de/a/b/"но http://codepad.org/hzpWmpzk нужен лучший навык написания кода.
Мне понравилось несколько представленных решений. Но те, кто делает замену всех '/+' в '/' (регулярные выражения) забывают, что ОС.путь.join () от python может обрабатывать этот вид соединения:
os.path.join('http://example.com/parent/path', 'subdir/file.html')результат:'http://example.com/parent/path/subdir/file.html'
Comments