PHP cURL: получить цель перенаправления, не следуя ей

Функция curl_getinfo возвращает много метаданных о результате запроса HTTP. Однако по какой-то причине он не включает бит информации, который я хочу в данный момент, который является целевым URL, если запрос возвращает код перенаправления HTTP.

Я не использую CURLOPT_FOLLOWLOCATION, потому что я хочу обрабатывать конкретные коды переадресации как особые случаи.

Если cURL может следовать за переадресацией, почему он не может сказать мне, к чему они перенаправляются, когда он не следует за ними?

Конечно, я могу установить флаг CURLOPT_HEADER и выбрать заголовок Location. Но есть ли более эффективный способ?

Solutions Collecting From Web of "PHP cURL: получить цель перенаправления, не следуя ей"

Это можно сделать за 4 простых шага:

Шаг 1. Инициализация завитка

curl_init($ch); //initialise the curl handle //COOKIESESSION is optional, use if you want to keep cookies in memory curl_setopt($this->ch, CURLOPT_COOKIESESSION, true); 

Шаг 2. Получите заголовки для $url

 curl_setopt($ch, CURLOPT_URL, $url); //specify your URL curl_setopt($ch, CURLOPT_HEADER, true); //include headers in http data curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); //don't follow redirects $http_data = curl_exec($ch); //hit the $url $curl_info = curl_getinfo($ch); $headers = substr($http_data, 0, $curl_info['header_size']); //split out header 

Шаг 3. Проверьте, есть ли у вас правильный код ответа

 if (!($curl_info['http_code']>299 && $curl_info['http_code']<309)) { //return, echo, die, whatever you like return 'Error - http code'.curl_info['http_code'].' received.'; } 

Шаг 4. Разделите заголовки, чтобы получить новый URL.

 preg_match("!\r\n(?:Location|URI): *(.*?) *\r\n!", $headers, $matches); $url = $matches[1]; 

После того, как у вас есть новый URL, вы можете повторять шаги 2-4 так часто, как вам нравится.

curl , похоже, не имеет функции или опции для получения перенаправленной цели, ее можно извлечь с помощью различных методов:

Из ответа :

Apache может отвечать HTML-страницей в случае перенаправления 301 (похоже, это не так с 302-ю).

Если ответ имеет формат, похожий на:

 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>301 Moved Permanently</title> </head><body> <h1>Moved Permanently</h1> <p>The document has moved <a href="http://www.xxx.yyy/zzz">here</a>.</p> <hr> <address>Apache/2.2.16 (Debian) Server at www.xxx.yyy Port 80</address> </body></html> 

Вы можете извлечь URL-адрес перенаправления с помощью DOMXPath :

 $i = 0; foreach($urls as $url) { if(substr($url,0,4) == "http") { $c = curl_init($url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); $result = @curl_exec($c); $status = curl_getinfo($c,CURLINFO_HTTP_CODE); curl_close($c); $results[$i]['code'] = $status; $results[$i]['url'] = $url; if($status === 301) { $xml = new DOMDocument(); $xml->loadHTML($result); $xpath = new DOMXPath($xml); $href = $xpath->query("//*[@href]")->item(0); $results[$i]['target'] = $href->attributes->getNamedItem('href')->nodeValue; } $i++; } } 

Использование CURLOPT_NOBODY

Однако существует более быстрый способ, как указывает @ gAMBOOKa ; Использование CURLOPT_NOBODY . Этот подход просто отправляет запрос HEAD вместо GET (не загружая фактический контент, поэтому он должен быть быстрее и эффективнее) и сохраняет заголовок ответа.

Используя регулярное выражение, целевой URL-адрес можно извлечь из заголовка:

 foreach($urls as $url) { if(substr($url,0,4) == "http") { $c = curl_init($url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_NOBODY,true); curl_setopt($c, CURLOPT_HEADER, true); $result = @curl_exec($c); $status = curl_getinfo($c,CURLINFO_HTTP_CODE); curl_close($c); $results[$i]['code'] = $status; $results[$i]['url'] = $url; if($status === 301 || $status === 302) { preg_match("@https?://([-\w\.]+)+(:\d+)?(/([\w/_\-\.]*(\?\S+)?)?)?@",$result,$m); $results[$i]['target'] = $m[0]; } $i++; } } 

Вы можете просто использовать его: (CURLINFO_REDIRECT_URL)

 $info = curl_getinfo($ch, CURLINFO_REDIRECT_URL); echo $info; // the redirect URL without following it 

как вы упомянули, отключите опцию CURLOPT_FOLLOWLOCATION (перед выполнением) и поместите мой код после выполнения.

CURLINFO_REDIRECT_URL – с отключенной опцией CURLOPT_FOLLOWLOCATION: URL-адрес перенаправления, найденный в последней транзакции, который следует запросить вручную далее. Если включена опция CURLOPT_FOLLOWLOCATION: она пуста. URL-адрес перенаправления в этом случае доступен в CURLINFO_EFFECTIVE_URL

Refrence

Нет более эффективного способа
Вы можете использовать CURLOPT_WRITEHEADER + VariableStream
Итак, вы можете написать заголовки переменной и проанализировать его

У меня была та же проблема и curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); оказал какую-либо помощь.

Итак, я решил не использовать CURL а file_get_contents :

 $data = file_get_contents($url); $data = str_replace("<meta http-equiv=\"Refresh\" content=\"0;","<meta",$data); 

Последняя строка помогла мне заблокировать перенаправление, хотя продукт не является чистым html-кодом.

Я проанализировал данные и мог получить URL-адрес перенаправления, который я хотел получить.