CURL kullanarak nereye yönlendirileceğimi nasıl bulabilirim?


149

Kıvrımı bir yönlendirmeyi takip etmeye çalışıyorum ama düzgün çalışmasını sağlayamıyorum. Bir sunucuya GET param olarak göndermek ve elde edilen URL almak istiyorum bir dize var.

Misal:

String = Kobold Vermin
URL'si = www.wowhead.com/search?q=Kobold+Worker

Bu URL'ye giderseniz sizi "www.wowhead.com/npc=257" adresine yönlendirir. Kıvırmak ben "npc = 257" ayıklamak ve kullanmak böylece benim PHP koduna bu URL dönmek istiyorum.

Mevcut kod:

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

Ancak bu, www.wowhead.com/npc=257 yerine www.wowhead.com/search?q=Kobold+Worker değerini döndürür .

Harici yönlendirme gerçekleşmeden önce PHP'nin geri döndüğünden şüpheleniyorum. Bunu nasıl düzeltebilirim?


8
Bu, "kıvrım izleme yönlendirmeleri" için en sık sorulan sorulardan biridir. curlKomutu kullanarak yönlendirmeleri otomatik olarak takip etmek için -Lveya --locationbayrağını iletin. Ör.curl -L http://example.com/
Rob W

Yanıtlar:


256

CURL'nin bir yönlendirmeyi takip etmesini sağlamak için şunu kullanın:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Hımm ... Aslında bukle işlemini yürüttüğünüzü sanmıyorum ... Deneyin:

curl_exec($ch);

... seçenekleri ayarladıktan sonra ve curl_getinfo()aramadan önce .

DÜZENLEME: Sadece öğrenmek istiyorsanız nerede tavsiyeye ediyorum, bir sayfası yönlendirmeleri burada ve sadece başlıkları kapmak için Curl kullanmak ve Yer ayıklamak: onlardan başlığı:

$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
Bu php yönlendirmeyi takip yapar. Yönlendirmeyi takip etmek istemiyorum, sadece yönlendirilen sayfanın URL'sini bilmek istiyorum.
Thomas Van Nuffel

9
Yani, aslında sayfayı getirmek istemiyor musunuz? Sadece yerini mi buldun? Bu durumda, burada kullanılan taktiği öneririm: zzz.rezo.net/HowTo-Expand-Short-URLs.html - temel olarak, yönlendiren sayfadaki üstbilgiyi alın ve Konum: üstbilgisini buradan alın. Her iki durumda da, Curl'un aslında bir şey yapması için yine de exec () yapmanız gerekiyor ...
Matt Gibson

1
Aşağıdaki Luca Camillos çözümüne bir göz atmanızı öneririm, çünkü bu çözüm birden fazla yönlendirmeyi dikkate almaz.
Christian Engel

bu çözüm yeni web sayfasını aynı url içinde açar. Ben de bu url parametreleri gönderme ile birlikte url değiştirmek istiyorum. Bunu nasıl başarabilirim?
amanpurohit

$ HttpCode = curl_getinfo ($ tanıtıcı, CURLINFO_HTTP_CODE) kullandığımda @MattGibson; CURLOPT_FOLLOWLOCATION doğru olarak ayarlandığında httpcode ne olur? İlk url için mi yoksa yönlendirme url'si için mi olacak
Manigandan Arjunan

26

Bu çizgiyi iniziyalizasyonu kıvırmak için ekleyin

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

ve curl_close'tan önce getinfo kullanın

$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
Bunun daha iyi bir çözüm olduğunu düşünüyorum, çünkü aynı zamanda birden fazla yönlendirmeyi de açıyor.
Christian Engel

Unutmayın: (tamam, duh) POST verileri bir yönlendirmeden sonra tekrar gönderilmez. Benim durumumda bu oldu ve daha sonra kendimi aptal gibi hissettim çünkü: sadece uygun url'yi kullanın ve düzeltildi.
twojjr

Kullanmak curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);bir güvenlik açığıdır. Temelde “Bozuksa SSL hatalarını yoksay - şifrelenmemiş bir URL'de olduğu gibi güvenin” diyor.
incelik

8

Yukarıdaki cevap benim sunucularımdan birinde benim için işe yaramadı, basedir ile bir şey, bu yüzden biraz yeniden hashed. Aşağıdaki kod tüm sunucularımda çalışıyor.

$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: Başlık bir yönlendirmeyi izlemek için her zaman değil. Ayrıca lütfen bununla ilgili açık bir soruya bakın: curl follow location error
hakre

5

Burada seçilen cevap iyi ama büyük / küçük harfe duyarlıdır, göreli location:üstbilgilere (bazı sitelerin yaptığı) veya Location:içeriklerinde gerçekten ifadesi olabilecek sayfalara karşı koruma sağlamaz ... (şu anda zillow'un yaptığı).

Biraz özensiz, ama bunu biraz daha akıllı hale getirmek için birkaç hızlı düzenleme:

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

Bunun hala yalnızca 1 yönlendirmenin daha derinine gittiğini unutmayın. Daha derine inmek için, aslında içeriği almanız ve yönlendirmeleri takip etmeniz gerekir.


5

Bazen HTTP üstbilgileri almanız gerekir, ancak aynı zamanda bu üstbilgileri döndürmek istemezsiniz. **

Bu iskelet özyineleme kullanarak çerezleri ve HTTP yönlendirmelerini halleder. Buradaki ana fikir, dönüş HTTP üstbilgilerinden kaçınmaktır istemci koduna .

Üzerinde çok güçlü bir kıvrılma sınıfı oluşturabilirsiniz. POST işlevselliği vb. Ekleyin.

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

Burada regex çok, onları gerçekten sevmeme rağmen bu şekilde benim için daha kararlı olabilir:

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

Konum bölümü, apache tarafından gönderilen HTML'deki bir bağlantıdır. Bu yüzden Xpath onu kurtarmak için mükemmeldir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.