2016-10-15 14 views
2

ベースURLと潜在的に相対的なパスからURLを構築するPHPとは何ですか? Pythonはurlparse.urljoinを提供していますが、PHPでは標準実装がないようです。Pythonの `urljoin`に相当するPHP

私が見つけた最も近い人々がparse_urlの使用を示唆して、パーツからURLを再構築するが、一般的にプロトコル相対リンクのようなものが誤解していることやって実装は、(例えば、//example.com/fooを継承し、http://example.com/fooまたはhttps://example.com/fooになりつつありますベースURLのプロトコル)、親ディレクトリリンクなどの処理も​​簡単にはできません。ここでurlparse.urljoinで正しく動作してそれらのものの例は以下のとおりです。

>>> from urlparse import urljoin 
>>> urljoin('http://example.com/some/directory/filepart', 'foo.jpg') 
'http://example.com/some/directory/foo.jpg' 
>>> urljoin('http://example.com/some/directory/', 'foo.jpg') 
'http://example.com/some/directory/foo.jpg' 
>>> urljoin('http://example.com/some/directory/', '../foo.jpg') 
'http://example.com/some/foo.jpg' 
>>> urljoin('http://example.com/some/directory/', '/foo.jpg') 
'http://example.com/foo.jpg' 
>>> urljoin('http://example.com/some/directory/', '//images.example.com/bar.jpg') 
'http://images.example.com/bar.jpg' 
>>> urljoin('https://example.com/some/directory/', '//images.example.com/bar.jpg') 
'https://images.example.com/bar.jpg' 
>>> urljoin('ftp://example.com/some/directory/', '//images.example.com/bar.jpg') 
'ftp://images.example.com/bar.jpg' 
>>> urljoin('http://example.com:8080/some/directory/', '//images.example.com/bar.jpg') 
'http://images.example.com/bar.jpg' 

は実際に正しいこれらの例すべてを取得するPHPで同じことを達成するための慣用的な方法、または定評のあるシンプルなライブラリや実装がありますか?

+0

私はあなたがそれを作らなければならないと信じています –

+0

@RyanVincent私はまだそれ以上の方法で 'parse_url'以上の何かをしていることはありません。相対パスの連結は、単にURL部分を無制限に置き換えるよりも複雑です。 – fluffy

答えて

2

明らかにこの機能が必要であり、そこにランダムなスクリプトが含まれていないので、私はproject on Githubを開始して正しく実行しようとしています。

次のようにurljoin()の実装では、現在、次のとおりです。

function urljoin($base, $rel) { 
    $pbase = parse_url($base); 
    $prel = parse_url($rel); 

    $merged = array_merge($pbase, $prel); 
    if ($prel['path'][0] != '/') { 
     // Relative path 
     $dir = preg_replace('@/[^/]*[email protected]', '', $pbase['path']); 
     $merged['path'] = $dir . '/' . $prel['path']; 
    } 

    // Get the path components, and remove the initial empty one 
    $pathParts = explode('/', $merged['path']); 
    array_shift($pathParts); 

    $path = []; 
    $prevPart = ''; 
    foreach ($pathParts as $part) { 
     if ($part == '..' && count($path) > 0) { 
      // Cancel out the parent directory (if there's a parent to cancel) 
      $parent = array_pop($path); 
      // But if it was also a parent directory, leave it in 
      if ($parent == '..') { 
       array_push($path, $parent); 
       array_push($path, $part); 
      } 
     } else if ($prevPart != '' || ($part != '.' && $part != '')) { 
      // Don't include empty or current-directory components 
      if ($part == '.') { 
       $part = ''; 
      } 
      array_push($path, $part); 
     } 
     $prevPart = $part; 
    } 
    $merged['path'] = '/' . implode('/', $path); 

    $ret = ''; 
    if (isset($merged['scheme'])) { 
     $ret .= $merged['scheme'] . ':'; 
    } 

    if (isset($merged['scheme']) || isset($merged['host'])) { 
     $ret .= '//'; 
    } 

    if (isset($prel['host'])) { 
     $hostSource = $prel; 
    } else { 
     $hostSource = $pbase; 
    } 

    // username, password, and port are associated with the hostname, not merged 
    if (isset($hostSource['host'])) { 
     if (isset($hostSource['user'])) { 
      $ret .= $hostSource['user']; 
      if (isset($hostSource['pass'])) { 
       $ret .= ':' . $hostSource['pass']; 
      } 
      $ret .= '@'; 
     } 
     $ret .= $hostSource['host']; 
     if (isset($hostSource['port'])) { 
      $ret .= ':' . $hostSource['port']; 
     } 
    } 

    if (isset($merged['path'])) { 
     $ret .= $merged['path']; 
    } 

    if (isset($prel['query'])) { 
     $ret .= '?' . $prel['query']; 
    } 

    if (isset($prel['fragment'])) { 
     $ret .= '#' . $prel['fragment']; 
    } 


    return $ret; 
} 

正しくにおける共通の欠陥であると思われるユーザー、パスワード、ポート番号、クエリ文字列、アンカー、とさえfile:/// URLを(処理するこの機能このタイプの既存の機能)。

+0

これは一般的な必要性のため、私は先に進み、githubプロジェクトを作成しました:https://github.com/plaidfluff/php-urljoin – fluffy

+0

良い仕事、私は私のプロジェクトでそれを使用しています –