2016-11-27 2 views
2

У меня есть Гуты/клиент (ГОУТТА использует Symfony для запросов), и я хотел бы присоединиться к пути и получить окончательный URL:Регистрация адреса в симфони/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/ГОУТТЕ/жрать дает любой простой способ сделать это?

Я нашел getUriForPath от Symfony\Component\HttpFoundation\Request, но я не вижу простой способ, чтобы преобразовать Symfony\Component\BrowserKit\Request в HttpFoundation\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 может помочь вам:

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

Все, что осталось сделать, это восстановление URL, вы можете увидеть 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

Я не уверен, как вы обрабатываете 'http: // example.org/page /', соединенный с '/ new_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 package. Этот метод позволяет создать нормализованный URL-адрес с базовой и относительной частей.

Пример (с использованием отлично 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