Làm cách nào để tìm nơi tôi sẽ được chuyển hướng bằng cURL?


149

Tôi đang cố gắng để làm cho curl theo một chuyển hướng nhưng tôi hoàn toàn không thể làm cho nó hoạt động đúng. Tôi có một chuỗi mà tôi muốn gửi dưới dạng tham số GET đến máy chủ và nhận URL kết quả.

Thí dụ:

Chuỗi = Kobold Vermin
Url = www.wowhead.com/search?q=Kobold+Worker

Nếu bạn truy cập url đó, nó sẽ chuyển hướng bạn đến "www.wowhead.com/npc=257". Tôi muốn curl trả lại URL này cho mã PHP của mình để tôi có thể trích xuất "npc = 257" và sử dụng nó.

Mã hiện tại:

function npcID($name) {
    $urltopost = "http://www.wowhead.com/search?q=" . $name;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1");
    curl_setopt($ch, CURLOPT_URL, $urltopost);
    curl_setopt($ch, CURLOPT_REFERER, "http://www.wowhead.com");
    curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:application/x-www-form-urlencoded"));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    return curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
}

Tuy nhiên, điều này trả về www.wowhead.com/search?q=Kobold+Worker chứ không phải www.wowhead.com/npc=257 .

Tôi nghi ngờ PHP sẽ trở lại trước khi chuyển hướng bên ngoài xảy ra. Làm thế nào tôi có thể sửa lỗi này?


8
Đây là một trong những câu hỏi hàng đầu cho "curl follow redirects". Để tự động theo dõi chuyển hướng bằng cách sử dụng curllệnh, vượt qua -Lhoặc --locationcờ. Ví dụ:curl -L http://example.com/
Rob W

Câu trả lời:


256

Để thực hiện cURL theo chuyển hướng, sử dụng:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Erm ... Tôi không nghĩ rằng bạn thực sự đang thực hiện curl ... Hãy thử:

curl_exec($ch);

... Sau khi cài đặt các tùy chọn và trước curl_getinfo()cuộc gọi.

EDIT: Nếu bạn chỉ muốn tìm ra nơi một trang chuyển hướng đến, tôi sẽ sử dụng lời khuyên ở đây và chỉ cần sử dụng Curl để lấy các tiêu đề và trích xuất tiêu đề Location: từ chúng:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (preg_match('~Location: (.*)~i', $result, $match)) {
   $location = trim($match[1]);
}

2
Điều này làm cho php theo chuyển hướng. Tôi không muốn làm theo chuyển hướng, tôi chỉ muốn biết url của trang được chuyển hướng.
Thomas Van Nuffel

9
Ồ, vậy là bạn không thực sự muốn tìm nạp trang? Chỉ cần tìm ra vị trí? Trong trường hợp đó, tôi đề xuất chiến thuật được sử dụng ở đây: zzz.rezo.net/HowTo-Expand-Short-URLs.html - về cơ bản chỉ cần lấy tiêu đề từ trang chuyển hướng và lấy tiêu đề Location: từ nó. Dù sao đi nữa, bạn vẫn cần phải thực hiện exec () để Curl thực sự làm bất cứ điều gì ...
Matt Gibson

1
Tôi khuyên bạn nên xem xét giải pháp Luca Camillos dưới đây, vì giải pháp này không cần xem xét nhiều lần chuyển hướng.
Christian Engel

giải pháp này mở trang web mới trong cùng một url. Tôi muốn thay đổi url cùng với việc đăng các tham số lên url đó. Làm thế nào tôi có thể đạt được điều đó?
amanpurohit

@MattGibson khi tôi sử dụng $ httpCode = curl_getinfo ($ xử lý, CURLINEFO_HTTP_CODE); với CURLOPT_FOLLOWLOCATION được đặt thành true, httpcode sẽ là gì. Ý tôi là nó sẽ dành cho url đầu tiên hoặc cho url chuyển hướng
Manigandan Arjunan

26

Thêm dòng này để cuộn tròn inizialization

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

và sử dụng getinfo trước khi curl_c Đóng

$redirectURL = curl_getinfo($ch,CURLINFO_EFFECTIVE_URL );

es:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$html = curl_exec($ch);
$redirectURL = curl_getinfo($ch,CURLINFO_EFFECTIVE_URL );
curl_close($ch);

2
Tôi nghĩ rằng đây là một giải pháp tốt hơn, bởi vì nó cũng mở ra nhiều chuyển hướng.
Christian Engel

Hãy nhớ rằng: (ok, duh) Dữ liệu POST sẽ không được gửi lại sau khi chuyển hướng. Trong trường hợp của tôi, điều này đã xảy ra và tôi cảm thấy ngu ngốc sau đó bởi vì: chỉ cần sử dụng url thích hợp và nó đã được sửa.
hai lần vào

Sử dụng curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);là một lỗ hổng bảo mật. Về cơ bản, nó nói rằng Bỏ qua các lỗi SSL nếu nó bị hỏng - hãy tin tưởng giống như một URL không được mã hóa.
Finesse

8

Câu trả lời ở trên không hoạt động với tôi trên một trong những máy chủ của tôi, một cái gì đó với cơ sở, vì vậy tôi đã băm lại nó một chút. Mã dưới đây hoạt động trên tất cả các máy chủ của tôi.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$a = curl_exec($ch);
curl_close( $ch ); 
// the returned headers
$headers = explode("\n",$a);
// if there is no redirection this will be the final url
$redir = $url;
// loop through the headers and check for a Location: str
$j = count($headers);
for($i = 0; $i < $j; $i++){
// if we find the Location header strip it and fill the redir var       
if(strpos($headers[$i],"Location:") !== false){
        $redir = trim(str_replace("Location:","",$headers[$i]));
        break;
    }
}
// do whatever you want with the result
echo redir;

Các Location: tiêu đề không phải lúc nào cũng tuân theo một chuyển hướng. Ngoài ra, vui lòng xem một câu hỏi rõ ràng về vấn đề này: curl follow lỗi vị trí
hakre

5

Câu trả lời được chọn ở đây là khá nhưng trường hợp nhạy cảm, không bảo vệ chống lại người thân location: các tiêu đề (mà một số trang web làm) hoặc các trang thực sự có cụm từLocation: trong nội dung của họ ... (hiện tại zirl hiện có).

Một chút cẩu thả, nhưng một vài chỉnh sửa nhanh chóng để làm cho điều này thông minh hơn một chút là:

function getOriginalURL($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    $result = curl_exec($ch);
    $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // if it's not a redirection (3XX), move along
    if ($httpStatus < 300 || $httpStatus >= 400)
        return $url;

    // look for a location: header to find the target URL
    if(preg_match('/location: (.*)/i', $result, $r)) {
        $location = trim($r[1]);

        // if the location is a relative URL, attempt to make it absolute
        if (preg_match('/^\/(.*)/', $location)) {
            $urlParts = parse_url($url);
            if ($urlParts['scheme'])
                $baseURL = $urlParts['scheme'].'://';

            if ($urlParts['host'])
                $baseURL .= $urlParts['host'];

            if ($urlParts['port'])
                $baseURL .= ':'.$urlParts['port'];

            return $baseURL.$location;
        }

        return $location;
    }
    return $url;
}

Lưu ý rằng điều này vẫn chỉ đi sâu 1 chuyển hướng. Để đi sâu hơn, bạn thực sự cần phải có được nội dung và làm theo các chuyển hướng.


5

Đôi khi bạn cần nhận các tiêu đề HTTP nhưng đồng thời bạn không muốn trả lại các tiêu đề đó. **

Bộ xương này chăm sóc cookie và chuyển hướng HTTP bằng cách sử dụng đệ quy. Ý tưởng chính ở đây là để tránh trả lại các tiêu đề HTTP cho mã máy khách.

Bạn có thể xây dựng một lớp curl rất mạnh trên nó. Thêm chức năng POST, v.v.

<?php

class curl {

  static private $cookie_file            = '';
  static private $user_agent             = '';  
  static private $max_redirects          = 10;  
  static private $followlocation_allowed = true;

  function __construct()
  {
    // set a file to store cookies
    self::$cookie_file = 'cookies.txt';

    // set some general User Agent
    self::$user_agent = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';

    if ( ! file_exists(self::$cookie_file) || ! is_writable(self::$cookie_file))
    {
      throw new Exception('Cookie file missing or not writable.');
    }

    // check for PHP settings that unfits
    // correct functioning of CURLOPT_FOLLOWLOCATION 
    if (ini_get('open_basedir') != '' || ini_get('safe_mode') == 'On')
    {
      self::$followlocation_allowed = false;
    }    
  }

  /**
   * Main method for GET requests
   * @param  string $url URI to get
   * @return string      request's body
   */
  static public function get($url)
  {
    $process = curl_init($url);    

    self::_set_basic_options($process);

    // this function is in charge of output request's body
    // so DO NOT include HTTP headers
    curl_setopt($process, CURLOPT_HEADER, 0);

    if (self::$followlocation_allowed)
    {
      // if PHP settings allow it use AUTOMATIC REDIRECTION
      curl_setopt($process, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($process, CURLOPT_MAXREDIRS, self::$max_redirects); 
    }
    else
    {
      curl_setopt($process, CURLOPT_FOLLOWLOCATION, false);
    }

    $return = curl_exec($process);

    if ($return === false)
    {
      throw new Exception('Curl error: ' . curl_error($process));
    }

    // test for redirection HTTP codes
    $code = curl_getinfo($process, CURLINFO_HTTP_CODE);
    if ($code == 301 || $code == 302)
    {
      curl_close($process);

      try
      {
        // go to extract new Location URI
        $location = self::_parse_redirection_header($url);
      }
      catch (Exception $e)
      {
        throw $e;
      }

      // IMPORTANT return 
      return self::get($location);
    }

    curl_close($process);

    return $return;
  }

  static function _set_basic_options($process)
  {

    curl_setopt($process, CURLOPT_USERAGENT, self::$user_agent);
    curl_setopt($process, CURLOPT_COOKIEFILE, self::$cookie_file);
    curl_setopt($process, CURLOPT_COOKIEJAR, self::$cookie_file);
    curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
    // curl_setopt($process, CURLOPT_VERBOSE, 1);
    // curl_setopt($process, CURLOPT_SSL_VERIFYHOST, false);
    // curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  }

  static function _parse_redirection_header($url)
  {
    $process = curl_init($url);    

    self::_set_basic_options($process);

    // NOW we need to parse HTTP headers
    curl_setopt($process, CURLOPT_HEADER, 1);

    $return = curl_exec($process);

    if ($return === false)
    {
      throw new Exception('Curl error: ' . curl_error($process));
    }

    curl_close($process);

    if ( ! preg_match('#Location: (.*)#', $return, $location))
    {
      throw new Exception('No Location found');
    }

    if (self::$max_redirects-- <= 0)
    {
      throw new Exception('Max redirections reached trying to get: ' . $url);
    }

    return trim($location[1]);
  }

}

0

Rất nhiều regex ở đây, mặc dù thực tế tôi thực sự thích chúng theo cách này có thể ổn định hơn với tôi:

$resultCurl=curl_exec($curl); //get curl result
//Optional line if you want to store the http status code
$headerHttpCode=curl_getinfo($curl,CURLINFO_HTTP_CODE);

//let's use dom and xpath
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($resultCurl, LIBXML_HTML_NODEFDTD);
libxml_use_internal_errors(false);
$xpath = new \DOMXPath($dom);
$head=$xpath->query("/html/body/p/a/@href");

$newUrl=$head[0]->nodeValue;

Phần vị trí là một liên kết trong HTML được gửi bởi apache. Vì vậy, Xpath là hoàn hảo để phục hồi nó.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.