Wie finde ich heraus, wo ich mit cURL umgeleitet werde?

148

Ich versuche, Curl einer Umleitung zu folgen, aber ich kann es nicht ganz zum Laufen bringen. Ich habe eine Zeichenfolge, die ich als GET-Parameter an einen Server senden und die resultierende URL abrufen möchte.

Beispiel:

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

Wenn Sie zu dieser URL gehen, werden Sie zu "www.wowhead.com/npc=257" weitergeleitet. Ich möchte, dass curl diese URL zu meinem PHP-Code zurückgibt, damit ich das "npc = 257" extrahieren und verwenden kann.

Aktueller Code:

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

Dies gibt jedoch www.wowhead.com/search?q=Kobold+Worker und nicht www.wowhead.com/npc=257 zurück .

Ich vermute, dass PHP zurückkehrt, bevor die externe Umleitung erfolgt. Wie kann ich das beheben?

Thomas Van Nuffel
quelle
8
Dies ist eine der wichtigsten Fragen für "Curl Follow Redirects". curlÜbergeben Sie das Flag -Loder, um Weiterleitungen mit dem Befehl automatisch zu verfolgen --location. ZBcurl -L http://example.com/
Rob W

Antworten:

256

Verwenden Sie Folgendes, um cURL einer Weiterleitung folgen zu lassen:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Ähm ... Ich glaube nicht, dass Sie die Locke tatsächlich ausführen ... Versuchen Sie:

curl_exec($ch);

... nach dem Einstellen der Optionen und vor dem curl_getinfo()Anruf.

BEARBEITEN: Wenn Sie nur herausfinden möchten, wohin eine Seite umgeleitet wird, verwende ich den Rat hier und verwende Curl, um die Überschriften zu erfassen und die Überschrift Location: aus ihnen zu extrahieren:

$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]);
}
Matt Gibson
quelle
2
Dadurch folgt PHP der Umleitung. Ich möchte der Weiterleitung nicht folgen, ich möchte nur die URL der umgeleiteten Seite kennen.
Thomas Van Nuffel
9
Oh, also wollen Sie die Seite eigentlich nicht abrufen? Finden Sie einfach den Ort heraus? In diesem Fall würde ich die hier verwendete Taktik vorschlagen: zzz.rezo.net/HowTo-Expand-Short-URLs.html - im Grunde genommen einfach den Header von der Seite, die umleitet, und den Location: Header von dort. In jedem Fall müssen Sie immer noch exec () ausführen, damit Curl tatsächlich etwas tut ...
Matt Gibson
1
Ich schlage vor, einen Blick auf die Luca Camillos-Lösung unten zu werfen, da diese Lösung nicht mehrere Weiterleitungen berücksichtigt.
Christian Engel
Diese Lösung öffnet die neue Webseite unter derselben URL. Ich möchte die URL auch zusammen mit dem Posten der Parameter in dieser URL ändern. Wie kann ich das erreichen?
Amanpurohit
@MattGibson, wenn ich $ httpCode = curl_getinfo verwende ($ handle, CURLINFO_HTTP_CODE); mit CURLOPT_FOLLOWLOCATION auf true gesetzt, was der httpcode sein wird. Ich meine, wird es für die erste URL oder für die Weiterleitungs-URL sein
Manigandan Arjunan
26

Fügen Sie diese Linie zur Curl-Inizialisierung hinzu

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

und benutze getinfo vor 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);
Luca Camillo
quelle
2
Ich denke, dies ist die bessere Lösung, da es auch mehrere Umleitungen entfaltet.
Christian Engel
Denken Sie daran: (ok, duh) POST-Daten werden nach einer Umleitung nicht erneut gesendet. In meinem Fall passierte dies und ich fühlte mich danach dumm, weil: benutze einfach die entsprechende URL und es ist behoben.
zweimal
Die Verwendung curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);ist eine Sicherheitslücke. Im Wesentlichen heißt es: "Ignorieren Sie die SSL-Fehler, wenn sie defekt sind - vertrauen Sie genauso wie einer unverschlüsselten URL."
Finesse
8

Die obige Antwort hat bei mir auf einem meiner Server nicht funktioniert, was mit basedir zu tun hat, also habe ich sie ein wenig überarbeitet. Der folgende Code funktioniert auf allen meinen Servern.

$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;
GR1NN3R
quelle
Der Location: Header soll nicht immer einer Umleitung folgen. Bitte
beachten
5

Die hier gewählte Antwort ist anständig, unterscheidet jedoch zwischen Groß- und Kleinschreibung und schützt nicht vor relativen location:Überschriften (was einige Websites tun) oder Seiten, Location:deren Inhalt möglicherweise tatsächlich den Ausdruck enthält ... (was zillow derzeit tut).

Ein bisschen schlampig, aber ein paar schnelle Änderungen, um dies ein bisschen schlauer zu machen, sind:

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

Beachten Sie, dass dies immer noch nur 1 Umleitung tief geht. Um tiefer zu gehen, müssen Sie tatsächlich den Inhalt abrufen und den Weiterleitungen folgen.

Broox
quelle
5

Manchmal müssen Sie HTTP-Header abrufen, aber gleichzeitig möchten Sie diese Header nicht zurückgeben. **

Dieses Skelett kümmert sich um Cookies und HTTP-Weiterleitungen mithilfe von Rekursion. Die Hauptidee hierbei ist, zu vermeiden, dass HTTP-Header an den Clientcode zurückgegeben werden.

Sie können eine sehr starke Curl-Klasse darüber aufbauen. POST-Funktionalität usw. hinzufügen

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

}
Igor Parra
quelle
0

Viele Regex hier, obwohl ich sie wirklich mag, könnte für mich stabiler sein:

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

Der Positionsteil ist ein Link im HTML-Code, der von Apache gesendet wird. Xpath ist also perfekt, um es wiederherzustellen.

Patrick Valibus
quelle
-1

Sie können verwenden:

$redirectURL = curl_getinfo($ch,CURLINFO_REDIRECT_URL);
Abhilash Nayak
quelle