【问题标题】:PHP cURL: Get target of redirect, without following itPHP cURL:获取重定向目标,而不跟随它
【发布时间】:2011-02-23 12:56:01
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我的程序实际上使用了正文,在那些 URL 不是重定向的情况下。所以这根本不会改善问题。我的查询基本上是关于是否有一种提取 Location 标头的方法可以节省在 PHP 代码中执行此操作的开销。

标签: php curl


【解决方案1】:

这可以通过 4 个步骤完成:

步骤 1. 初始化 curl

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。

【讨论】:

    【解决方案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】:

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

      来自回复

      Apache 可以在 301 重定向的情况下使用 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++;
          }
      }
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 对于我的目的来说似乎有点矫枉过正......也许我现在可以使用一个简单的回调来理解它们。
        【解决方案5】:

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

        【讨论】:

        • 在我看来,您试图阻止重定向的页面使用的是元刷新,而不是 HTTP 重定向。后者是我正在处理的。
        猜你喜欢
        • 2012-05-04
        • 1970-01-01
        • 2012-01-30
        • 2016-08-30
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多