2016-10-15 99 views
2

什麼是從基本URL和潛在相對路徑構建URL的PHP​​等價物? Python提供了urlparse.urljoin,但在PHP中似乎沒有任何標準實現。PHP等效於Python的`urljoin`

我發現的最接近的是人們暗示使用parse_url,然後重建從零件的URL,但實現這樣做,通常得到像協議相對鏈接錯誤(例如,//example.com/foo變成http://example.com/foohttps://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我還沒有看到任何東西,只是更多的OO方式''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:///網址(這似乎是在一個共同的缺陷這種類型的現有功能)。

+0

因爲這個共同的需要,我繼續前進,只是做了一個github項目:https://github.com/plaidfluff/php-urljoin – fluffy

+0

好的工作,我在我的項目中使用它 –