PHP cURL: получить цель перенаправления, не следуя ей - PullRequest
8 голосов
/ 23 февраля 2011

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

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

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

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

Ответы [ 5 ]

5 голосов
/ 04 апреля 2013

Это можно сделать за 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 столько раз, сколько захотите.

3 голосов
/ 15 января 2016

Вы можете просто использовать его: (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

2 голосов
/ 23 июля 2012

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++;
    }
}
0 голосов
/ 28 декабря 2015

У меня была та же проблема, и 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 перенаправления, который я хотел получить.

0 голосов
/ 25 февраля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...