2016-11-27 45 views
2

我有一個GOUTTE /客戶端(GOUTTE用來請求symfony的),我想加入的路徑,並獲得最終的URL:加入了symfony/GOUTTE網址

$client = new Goutte\Client(); 
$crawler = $client->request('GET', 'http://DOMAIN/some/path/') 
// $crawler is instance of Symfony\Component\DomCrawler\Crawler 

$new_path = '../new_page'; 
$final path = $crawler->someMagicFunction($new_path); 
// final path == http://DOMAIN/some/new_page 

我正在尋找的是一個簡單的方法加入$new_path變量與請求中的當前頁面並獲取新的URL。

注意$new_page可以是任何的:

new_page ==> http://DOMAIN/some/path/new_page 
../new_page ==> http://DOMAIN/some/new_page 
/new_page ==> http://DOMAIN/new_page 

是否symfony中/ GOUTTE /狂飲提供任何簡單的方法來做到這一點?

我發現getUriForPathSymfony\Component\HttpFoundation\Request,但我看不出有什麼簡單的方法來轉換Symfony\Component\BrowserKit\RequestHttpFoundation\Request

+0

你真的需要推崇的URL的路徑? guzzle應該可以在不出現問題的情況下處理對「http:// DOMAIN/some/path /../ new_page」的請求 – Federkun

+0

是的,我需要它進行其他驗證(而不是針對特定請求)。另外 - 如果'$ new_page'是'/ new_page',那麼最終的URL可能會有問題。 – Dekel

回答

1

您可以使用parse_url得到的URL路徑:

$components = parse_url('http://DOMAIN/some/path/'); 
$path = $components['path']; 

那麼你需要一種方法來標準化它。 This answer可以幫助你:那剩下來要做的就是重建URL

function normalizePath($path, $separator = '\\/') 
{ 
    // Remove any kind of funky unicode whitespace 
    $normalized = preg_replace('#\p{C}+|^\./#u', '', $path); 

    // Path remove self referring paths ("/./"). 
    $normalized = preg_replace('#/\.(?=/)|^\./|\./$#', '', $normalized); 

    // Regex for resolving relative paths 
    $regex = '#\/*[^/\.]+/\.\.#Uu'; 

    while (preg_match($regex, $normalized)) { 
     $normalized = preg_replace($regex, '', $normalized); 
    } 

    if (preg_match('#/\.{2}|\.{2}/#', $normalized)) { 
     throw new LogicException('Path is outside of the defined root, path: [' . $path . '], resolved: [' . $normalized . ']'); 
    } 

    return trim($normalized, $separator); 
} 

的一切,你可以看到this comment

function unparse_url($parsed_url) { 
    $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; 
    $host  = isset($parsed_url['host']) ? $parsed_url['host'] : ''; 
    $port  = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; 
    $user  = isset($parsed_url['user']) ? $parsed_url['user'] : ''; 
    $pass  = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; 
    $pass  = ($user || $pass) ? "[email protected]" : ''; 
    $path  = isset($parsed_url['path']) ? $parsed_url['path'] : ''; 
    $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; 
    $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; 
    return "$scheme$user$pass$host$port/$path$query$fragment"; 
} 

最終路徑:

$new_path = '../new_page'; 

if (strpos($new_path, '/') === 0) { // absolute path, replace it entirely 
    $path = $new_path; 
} else { // relative path, append it 
    $path = $path . $new_path; 
} 

把它放在一起:

// http://DOMAIN/some/new_page 
echo unparse_url(array_replace($components, array('path' => normalizePath($path)))); 
+0

感謝您的回答,我希望Symfony會爲此提供更簡單的解決方案。希望你不介意 - 我會稍等一會,然後把這個標記爲正確的答案,也許有人會有更好的解決方案。 – Dekel

+0

我不知道你如何處理用'/ new_page'加入的'http:// example.org/page /'(最終的url應該是'http:// example.org/new_page')。你可以解釋嗎? – Dekel

+0

最後一個例子('echo resolveUrl('http://example.org/page/','/ new_page'),「\ n」;')給出了http:// example.org/page而不是' HTTP:// example.org/new_page'。 – Dekel

3

使用Uri::resolve()guzzlehttp/prs7包。此方法允許您創建一個規範化的網址,該網址來自基本和相關部分。

一個例子(使用優良psysh shell):

Psy Shell v0.7.2 (PHP 7.0.12 — cli) by Justin Hileman 
>>> $base = new GuzzleHttp\Psr7\Uri('http://example.com/some/dir') 
=> GuzzleHttp\Psr7\Uri {#208} 
>>> (string) GuzzleHttp\Psr7\Uri::resolve($base, '/new_base/next/next/../../back_2') 
=> "http://example.com/new_base/back_2" 

此外看一看UriNormalizer class。有一個示例(test case)與您的問題相關。

從測試情況:

$uri = new Uri('http://example.org/../a/b/../c/./d.html'); 
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS); 

$this->assertSame('http://example.org/a/c/d.html', (string) $normalizedUri); 
+0

我不知道你如何處理'http:// example.org/page /'加入'/ new_page'(最終的url應該是http:// example.org/new_page')。你可以解釋嗎? – Dekel

+0

你說得對。剛剛用'guzzlehttp/prs7'更新了答案正確的解決方案。 –

+0

謝謝。這似乎是我使用的goutte版本有點舊,並沒有guzzle的最新版本(它有prs7和UriResolve)。但你在這裏得到我的讚揚:)再次感謝您的幫助! – Dekel