2009-07-07 17 views
50

PHPにインテリジェントにパス文字列を結合する組み込み関数はありますか?引数として "abc/de /"と "/fg/x.php"を指定した関数は、 "abc/de/fg/x.php"を返すべきです。その関数の引数として "abc/de"と "fg/x.php"を使用して同じ結果を与える必要があります。PHPでファイルシステムパス文字列に参加するには?

利用できない場合は、利用可能なクラスがありますか?パスを分割したり、パスの一部を削除したりするのにも役立ちます。あなたが何かを書いたのであれば、あなたのコードをここで共有してもよいでしょうか?

"/"を使用するのは問題ありません。私はLinuxのみをコーディングしています。

Pythonにはos.path.join()があり、これは素晴らしいです。

+1

によってコメントからコピーうわー、私はGoogleからのここに来ています。 PHPがこのようなものだとは信じられません。 –

+4

'os.path.join( 'some/relative/path、'/an/absolute/path ')'は常に '/ an/absolute/path'を返すので、あなたの例はかなり誤解を招くことに注意してください。だから、絶対パスが2番目(またはn番目)に来るということを除けば、 'os.path.join'の代わりに(あるいは自分の例を修正して)、それに近いものを探しています。 – Tibo

+0

@Tiboと彼のコメントのアップリスト:いいえ、この例は疑問の要点を無視し、方向性の限界的な発言であるPythonリファレンスを強調することを主張する場合を除いて、誤解を招くものではありません。質問は、それが何を望んでいるかについて完全にはっきりとしています。それはちょうど 'os.path.join'ではありません。 '' abc/de/'と'/fg/x.php'を引数として与えられた関数は 'abc/de/fg/x.php'を返すべきです。 –

答えて

41

これは人気のある質問で、コメントは「機能の提案」または「バグレポート」で埋められているので...このコードスニペットは、2つの文字列をスラッシュで区切ります。それで全部です。それ以上はない。ハードディスク上の実際のパスを評価したり、実際に開始スラッシュを保持したりすることはありません。必要に応じてこのコードを追加してください。開始スラッシュなしのコードが常に返されます。

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

最終結果は常に最初と最後にスラッシュなしと以内にダブルスラッシュとパスになります。自由に機能してください。

EDIT: 上記のスニペット用の素晴らしい柔軟な関数ラッパーです。あなたが参加するため http://nz2.php.net/manual/en/function.pathinfo.php

パス情報を使用することができますパスの一部を取得するためのO)

+2

関数pj($ a、$ b){return rtrim($ a、 '/')。 '/'。 ltrim($ b、 '/'); } – user89021

+2

これは説明どおりに動作するとは限りません。 joinPaths( ''、 'foo.jpg')は '/foo.jpg'になります。私は、私のPHPファイルマネージャがファイルシステムのルートにユーザーが作成したファイルを書き始めた後、これに気づいた!修正されたバージョンでは、空の文字列であるパスは削除されます。 – Dwayne

+0

@Joe私は最初の引数が空である理由を最初に質問します。空のセグメントを除外するように更新されています。 – deceze

2

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/'); 

:あなたが好きなあなたは、どちらかのアレイまたは個別の引数として、できるだけ多くのパススニペットを渡すことができます@decezeからの応答はきれいに見えます

4

代わりに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 
+0

URL「/ offset/0/limit/1」を試してください。 – Danon

16

@ 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); 
} 
1

これは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; 
} 
2

' になり、別の方法:

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

私のテイク:

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())); 
} 

この1つは、お使いのOSに合わせて、任意のスラッシュが修正されます削除されません先頭のスラッシュ、複数のスラッシュを連続してクリーンアップします。

+12

常に絶対パスを作成しますが、少なくとも誰かがDIRECTORY_SEPARATORを言いました... –

87
function join_paths() { 
    $paths = array(); 

    foreach (func_get_args() as $arg) { 
     if ($arg !== '') { $paths[] = $arg; } 
    } 

    return preg_replace('#/+#','/',join('/', $paths)); 
} 

私の解決策は簡単で、Pythonのos.path.joinは、ファイル/ディレクトリが存在することがわかっている場合は

をすることができます、これらのテストケース

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' 
+4

これは質問に最もよくマッチするので、これは最良の答えです - これは 'os.path.join'に最も近く、知的にパス文字列を結合します* 。その答えは、 'os.path.join'の" reference "実装を追加し、ルールを破るOP固有のものを指定することで改善できます(テストケース' ['abc'、 '/ def'] 'は間違っていますos .path.join'ですが、質問ごとに正しいです)。 – Tibo

+4

常に 'DIRECTORY_SEPARATOR'を使うべきです... – Qix

+0

@qixなぜですか? Windowsはスラッシュをうまく理解します。 –

1

を考えてみましょ動作する方法と似ています余分なスラッシュを(それが不要である)、そして、実パスを呼び出す追加すなわち

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

もちろんこれはPythonバージョンと全く同じことではありませんが、多くの場合、十分に良いかもしれません。ここで

0

Node's 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); 
} 

テストケース:

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' 
-6

私が提示いくつかのソリューションが好きでした。

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

結果:「http://example.com/parent/path/subdir/file.html

しかし置き換えるない人たちは、すべての「/ +」に「/」のpythonからそのos.path.join()を忘れている(正規表現)が参加し、この種を扱うことができます
+0

PHPに質問しました。答えはPythonです – Toilal

1

これは非常にうまくいくように思えますし、私にはかなりうまく見えます。

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

Ricardo Galliの偉大な答えから、プロトコルの接頭辞を削除することを避けるための改良。

考えられるのは、1つの引数でプロトコルの存在をテストし、それを結果に維持することです。警告:これは簡単な実装です!例えば

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

結果

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

の代わりに、(プロトコルを殺す)

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

(プロトコルを維持)するのではなく、より良いコードを書くスキルをhttp://codepad.org/hzpWmpzk必要があります。見つかっ

1

ベストソリューション:

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

注:user89021

関連する問題