Come posso trovare dove verrò reindirizzato usando cURL?


149

Sto cercando di fare in modo che il ricciolo segua un reindirizzamento, ma non riesco proprio a farlo funzionare correttamente. Ho una stringa che voglio inviare come parametro GET a un server e ottenere l'URL risultante.

Esempio:

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

Se vai a quell'URL ti reindirizzerà a "www.wowhead.com/npc=257". Voglio curl per restituire questo URL al mio codice PHP in modo da poter estrarre "npc = 257" e usarlo.

Codice attuale:

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

Questo tuttavia restituisce www.wowhead.com/search?q=Kobold+Worker e non www.wowhead.com/npc=257 .

Sospetto che PHP stia tornando prima che avvenga il reindirizzamento esterno. Come posso risolvere questo problema?


8
Questa è una delle domande principali per "curl follow redirect". Per seguire automaticamente i reindirizzamenti utilizzando il curlcomando, passare il flag -Lo --location. Ad esempiocurl -L http://example.com/
Rob W,

Risposte:


256

Per fare in modo che cURL segua un reindirizzamento, utilizzare:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Ehm ... non penso che tu stia effettivamente eseguendo il ricciolo ... Prova:

curl_exec($ch);

... dopo aver impostato le opzioni e prima della curl_getinfo()chiamata.

EDIT: Se vuoi solo scoprire dove reindirizza una pagina, vorrei usare i consigli qui e usare semplicemente Curl per afferrare le intestazioni ed estrarre la posizione: header da loro:

$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
Questo fa in modo che php segua il reindirizzamento. Non voglio seguire il reindirizzamento, voglio solo conoscere l'URL della pagina reindirizzata.
Thomas Van Nuffel,

9
Oh, quindi non vuoi davvero recuperare la pagina? Scopri la posizione? In tal caso, suggerirei la tattica usata qui: zzz.rezo.net/HowTo-Expand-Short-URLs.html - in pratica basta prendere l'intestazione dalla pagina che reindirizza e afferrare la posizione: intestazione da essa. Ad ogni modo, comunque, devi ancora fare il exec () affinché Curl faccia effettivamente qualsiasi cosa ...
Matt Gibson,

1
Suggerisco di dare un'occhiata alla soluzione di Luca Camillos di seguito, perché questa soluzione non prende in considerazione più reindirizzamenti.
Christian Engel,

questa soluzione apre la nuova pagina Web all'interno dello stesso URL. Voglio cambiare l'URL anche insieme alla pubblicazione dei parametri in quell'URL. Come posso raggiungerlo?
amanpurohit,

@MattGibson quando utilizzo $ httpCode = curl_getinfo ($ handle, CURLINFO_HTTP_CODE); con CURLOPT_FOLLOWLOCATION impostato su true quale sarà il codice http. Voglio dire, sarà per il primo url o per l'URL di reindirizzamento
Manigandan Arjunan,

27

Aggiungi questa linea per arricciare l'inizializzazione

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

e usa getinfo prima di 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
Penso che questa sia la soluzione migliore, perché sviluppa anche reindirizzamenti multipli.
Christian Engel,

Ricorda: (ok, duh) i dati POST non verranno reinviati dopo un reindirizzamento. Nel mio caso è successo e dopo mi sono sentito stupido perché: basta usare l'URL appropriato ed è riparato.
volte

L'utilizzo curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);è una vulnerabilità di sicurezza. Sostanzialmente dice "Ignora gli errori SSL se è rotto - fidati dello stesso di un URL non crittografato".
Finesse

8

La risposta sopra non ha funzionato per me su uno dei miei server, qualcosa su cui basarmi con basedir, quindi l'ho ripetuta un po '. Il codice seguente funziona su tutti i miei server.

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

L' Location: intestazione non è sempre seguire un reindirizzamento. Vedi anche una domanda esplicitamente a riguardo: curl follow errore di posizione
hakre

5

La risposta scelta qui è decente ma sensibile al maiuscolo / minuscolo, non protegge dalle relative location:intestazioni (che alcuni siti fanno) o dalle pagine che potrebbero effettivamente avere la frase Location:nei loro contenuti ... (cosa che zillow attualmente fa).

Un po 'sciatto, ma un paio di modifiche rapide per renderlo un po' più intelligente sono:

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

Si noti che questo continua ancora solo 1 reindirizzamento in profondità. Per approfondire, devi effettivamente ottenere il contenuto e seguire i reindirizzamenti.


5

A volte è necessario ottenere le intestazioni HTTP ma allo stesso tempo non si desidera restituire quelle intestazioni. **

Questo scheletro si occupa dei cookie e dei reindirizzamenti HTTP utilizzando la ricorsione. L'idea principale qui è evitare di restituire le intestazioni HTTP al codice client.

Puoi costruire una classe di curl molto forte su di essa. Aggiungi funzionalità POST, ecc.

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

C'è molta regex qui, nonostante il fatto che mi piacciano davvero in questo modo potrebbe essere più stabile per me:

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

La parte della posizione è un collegamento nel codice HTML inviato da apache. Quindi Xpath è perfetto per recuperarlo.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.