PHP cURL:获取重定向的目标,而不是遵循它

时间:2011-02-23 12:56:02

标签: php curl

curl_getinfo函数返回有关HTTP请求结果的大量元数据。但是,由于某种原因,它不包括我想要的信息,如果请求返回HTTP重定向代码,则是目标URL。

我没有使用CURLOPT_FOLLOWLOCATION,因为我想将特定的重定向代码作为特殊情况处理。

如果cURL可以遵循重定向,为什么它不能告诉我当它没有跟随它们时重定向到什么?

当然,我可以设置CURLOPT_HEADER标志并选择Location标头。但是有更有效的方法吗?

5 个答案:

答案 0 :(得分:4)

这可以通过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.解析标题以获取新网址

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

获得新网址后,您可以随时重复步骤2-4。

答案 1 :(得分:2)

curl似乎没有获取重定向目标的功能或选项,可以使用各种技术提取它:

来自回复

如果是301重定向,Apache可以使用HTML页面进行响应(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>

您可以使用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++;
    }
}

答案 2 :(得分:2)

你可以简单地使用它:(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选项   disabled:在上一个事务中找到的重定向URL,应该是   接下来手动请求。使用CURLOPT_FOLLOWLOCATION选项   启用:这是空的。在这种情况下,重定向URL可用于   CURLINFO_EFFECTIVE_URL

Refrence

答案 3 :(得分:0)

没有更有效的方式
您可以使用CURLOPT_WRITEHEADER + VariableStream
所以..你可以将标题写入变量并解析它

答案 4 :(得分:0)

我遇到了同样的问题,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代码。

我解析了数据并可以检索我想要的重定向网址。