Функция curl_getinfo возвращает много метаданных о результате запроса HTTP. Однако по какой-то причине он не включает бит информации, который я хочу в данный момент, который является целевым URL, если запрос возвращает код перенаправления HTTP.
Я не использую CURLOPT_FOLLOWLOCATION, потому что я хочу обрабатывать конкретные коды переадресации как особые случаи.
Если cURL может следовать за переадресацией, почему он не может сказать мне, к чему они перенаправляются, когда он не следует за ними?
Конечно, я могу установить флаг CURLOPT_HEADER и выбрать заголовок Location. Но есть ли более эффективный способ?
Это можно сделать за 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-адрес перенаправления, который я хотел получить.