ฉันจะหาที่ฉันจะถูกเปลี่ยนเส้นทางโดยใช้ cURL ได้อย่างไร


149

ฉันพยายามที่จะม้วนงอตามการเปลี่ยนเส้นทาง แต่ฉันไม่สามารถทำให้มันทำงานได้ ฉันมีสตริงที่ฉันต้องการส่งเป็น GET Param ไปยังเซิร์ฟเวอร์และรับ URL ที่เป็นผลลัพธ์

ตัวอย่าง:

String = Kobold Vermin
Url = www.wowhead.com/search?q=Kobold+Worker

หากคุณไปที่ URL ดังกล่าวระบบจะนำคุณไปยัง "www.wowhead.com/npc=257" ฉันต้องการให้ curl คืนค่า URL นี้ไปยังโค้ด PHP ของฉันเพื่อให้สามารถแยก "npc = 257" และใช้งานได้

รหัสปัจจุบัน:

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);
}

อย่างไรก็ตามเรื่องนี้จะส่งกลับwww.wowhead.com/search?q=Kobold+Workerและไม่www.wowhead.com/npc=257

ฉันสงสัยว่า PHP กำลังกลับมาก่อนที่การเปลี่ยนเส้นทางภายนอกจะเกิดขึ้น ฉันจะแก้ไขสิ่งนี้ได้อย่างไร


8
นี่เป็นหนึ่งในคำถามยอดนิยมสำหรับ "curl follow redirects" หากต้องการติดตามการเปลี่ยนเส้นทางโดยอัตโนมัติโดยใช้curlคำสั่งให้ส่งผ่าน-Lหรือ--locationตั้งค่าสถานะ เช่นcurl -L http://example.com/
Rob W

คำตอบ:


256

ในการทำให้ cURL ติดตามการเปลี่ยนเส้นทางให้ใช้:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

เอิ่ม ... ฉันไม่คิดว่าคุณกำลังทำ curl จริง ๆ ... ลอง:

curl_exec($ch);

... หลังจากตั้งค่าตัวเลือกและก่อนการcurl_getinfo()โทร

แก้ไข: หากคุณต้องการทราบว่าหน้าเปลี่ยนเส้นทางไปที่ใดฉันจะใช้คำแนะนำที่นี่และใช้ Curl เพื่อดึงส่วนหัวและแยกที่อยู่: ส่วนหัวจากพวกเขา:

$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
สิ่งนี้ทำให้ PHP ติดตามการเปลี่ยนเส้นทาง ฉันไม่ต้องการติดตามการเปลี่ยนเส้นทางฉันแค่ต้องการทราบ URL ของหน้าเปลี่ยนเส้นทาง
Thomas Van Nuffel

9
โอ้คุณไม่ต้องการดึงข้อมูลหน้าจริง ๆ หรือ เพิ่งทราบตำแหน่ง ในกรณีนั้นฉันขอแนะนำชั้นเชิงที่ใช้ที่นี่: zzz.rezo.net/HowTo- ขยาย-Short - URLs.html - โดยทั่วไปเพียงแค่ดึงส่วนหัวจากหน้าเว็บที่เปลี่ยนเส้นทางและรับตำแหน่ง: ส่วนหัวจากมัน แม้ว่าทั้งสองวิธีคุณจะยังคงต้องทำ exec () เพื่อให้ Curl ทำอะไรจริงๆ ...
แมตต์กิบสัน

1
ฉันขอแนะนำให้ดูที่โซลูชัน Luca Camillos ด้านล่างเนื่องจากโซลูชันนี้ไม่ได้พิจารณาการเปลี่ยนเส้นทางหลายครั้ง
Christian Engel

วิธีนี้จะเปิดหน้าเว็บใหม่ภายใน URL เดียวกัน ฉันต้องการเปลี่ยน URL พร้อมกับโพสต์พารามิเตอร์ไปยัง URL นั้น ฉันจะบรรลุสิ่งนั้นได้อย่างไร
amanpurohit

@MattGibson เมื่อฉันใช้ $ httpCode = curl_getinfo ($ handle, CURLINFO_HTTP_CODE); ด้วย CURLOPT_FOLLOWLOCATION ตั้งค่าเป็นจริงสิ่งที่จะเป็น httpcode ฉันหมายความว่ามันจะเป็นสำหรับ URL แรกหรือ URL เปลี่ยนเส้นทาง
Manigandan Arjunan

26

เพิ่มบรรทัดนี้เพื่อขด inizialization

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

และใช้ getinfo ก่อนที่จะ curl_close

$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
ฉันคิดว่าอันนี้เป็นทางออกที่ดีกว่าเพราะมันยังเผยการเปลี่ยนเส้นทางหลายครั้ง
Christian Engel

โปรดจำไว้ว่า: (ตกลงแล้ว duh) ข้อมูล POST จะไม่ถูกส่งอีกครั้งหลังจากเปลี่ยนเส้นทาง ในกรณีของฉันสิ่งนี้เกิดขึ้นและฉันรู้สึกงี่เง่าหลังจากนั้นเพราะเพียงแค่ใช้ URL ที่เหมาะสมและได้รับการแก้ไข
'172

การใช้curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);เป็นช่องโหว่ความปลอดภัย โดยพื้นฐานแล้วจะพูดว่า“ ไม่ต้องสนใจข้อผิดพลาด SSL ถ้ามันเสีย - เชื่อถือเช่นเดียวกับที่คุณทำกับ URL ที่ไม่ได้เข้ารหัส”
กลเม็ดเด็ดพราย

8

คำตอบข้างต้นไม่ได้ผลสำหรับฉันบนเซิร์ฟเวอร์ตัวใดตัวหนึ่งของฉันกับบางสิ่งบางอย่างในการใช้เบสฉันจึงแฮชอีกครั้ง รหัสด้านล่างใช้ได้กับเซิร์ฟเวอร์ของฉันทั้งหมด

$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;

Location: ส่วนหัวจะไม่เสมอที่จะทำตามการเปลี่ยนเส้นทาง นอกจากนี้โปรดดูคำถามที่ชัดเจนเกี่ยวกับเรื่องนี้: ข้อผิดพลาดในการติดตามตำแหน่ง
hakre

5

คำตอบที่เลือกไว้ที่นี่เหมาะสม แต่ตรงตามตัวพิมพ์ใหญ่ - เล็กไม่ได้ป้องกันlocation:ส่วนหัวที่เกี่ยวข้อง(ซึ่งบางไซต์ทำ) หรือหน้าเว็บที่อาจมีวลีLocation:ในเนื้อหาของพวกเขา ...

บิตเลอะเทอะ แต่การแก้ไขอย่างรวดเร็วสองสามครั้งเพื่อทำให้บิตนี้ฉลาดขึ้นคือ:

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;
}

โปรดทราบว่าสิ่งนี้ยังคงเปลี่ยนเส้นทางเพียง 1 ครั้งเท่านั้น หากต้องการลึกคุณจำเป็นต้องได้รับเนื้อหาและติดตามการเปลี่ยนเส้นทาง


5

บางครั้งคุณต้องรับส่วนหัว HTTP แต่ในเวลาเดียวกันคุณไม่ต้องการส่งคืนส่วนหัวเหล่านั้น **

โครงกระดูกนี้ดูแลคุกกี้และการเปลี่ยนเส้นทาง HTTP โดยใช้การเรียกซ้ำ แนวคิดหลักที่นี่คือการหลีกเลี่ยงการส่งคืนส่วนหัว HTTP กลับไปที่รหัสลูกค้า

คุณสามารถสร้างชั้นเรียนที่แข็งแรงมาก ๆ เพิ่มฟังก์ชั่น POST ฯลฯ

<?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

มี regex มากมายที่นี่แม้ว่าฉันจะชอบพวกเขาแบบนี้จริงๆอาจจะมีเสถียรภาพมากขึ้นสำหรับฉัน:

$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;

ส่วนที่ตั้งเป็นลิงค์ใน HTML ที่ส่งโดย apache ดังนั้น Xpath จึงสมบูรณ์แบบในการกู้คืน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.