2010-08-19 7 views
121

Sto cercando di far seguire a curl un reindirizzamento ma non riesco a farlo funzionare correttamente. Ho una stringa che voglio inviare come parametro GET a un server e ottenere l'URL risultante.Come posso trovare dove sarò reindirizzato usando cURL?

Esempio:

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

Se si va a tale URL essa ti reindirizzerà a "www.wowhead.com/npc=257". Voglio curl per restituire questo URL al mio codice PHP in modo da poter estrarre il "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 però torna www.wowhead.com/search?q=Kobold+Worker e non www.wowhead.com/npc=257.

Sospetto che PHP stia tornando prima che si verifichi il reindirizzamento esterno. Come posso risolvere questo?

+6

Questa è una delle principali domande per "curl follow reindirizza". Per seguire automaticamente i reindirizzamenti usando il comando 'curl', passa il flag' -L' o '--location'. Per esempio. 'arricciatura -L http: // example.com /' –

risposta

214

Per effettuare cURL seguire un reindirizzamento, uso:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 

Ehm ... non credo che si sta effettivamente eseguendo il riccio ... Prova:

curl_exec($ch);

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

EDIT: Se si desidera solo per scoprire dove una pagina di redirect, userei i consigli here, e basta usare Curl per afferrare le intestazioni ed estrarre la Località: colpo di testa 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]); 
} 
+1

Ciò fa sì che php segua il reindirizzamento. Non voglio seguire il reindirizzamento, voglio solo sapere l'url della pagina reindirizzata. –

+8

Oh, quindi in realtà non vuoi recuperare la pagina? Basta scoprire la posizione? In tal caso, suggerirei la tattica usata qui: http://zzz.rezo.net/HowTo-Expand-Short-URLs.html - in pratica basta prendere l'intestazione dalla pagina che reindirizza e afferrare la posizione: intestazione da esso. Ad ogni modo, devi comunque eseguire exec() per Curl in realtà _do_ qualsiasi cosa ... –

+4

Grazie, ha funzionato come un fascino :) –

8

La risposta sopra non ha funzionato per me su uno dei miei server, qualcosa da fare con basedir, quindi l'ho reinterpretato un po '. Il codice qui sotto 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; 
+0

L'intestazione 'Location:' non sempre segue un reindirizzamento. Si prega di vedere anche una domanda esplicitamente su questo: [curl seguire l'errore di posizione] (http://stackoverflow.com/questions/2511410/curl-follow-location-error) – hakre

4

La risposta scelta qui è decente, ma la sua maiuscole e minuscole, non protegge contro relativi location: intestazioni (che alcuni siti fanno) o le pagine che potrebbero in realtà avere la frase Location: nel loro contenuto ... (che Zillow attualmente fa).

Un po 'sciatta, ma un paio di rapide modifiche per rendere questo 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 ancora va solo 1 reindirizzamento profonda. Per approfondire, devi effettivamente ottenere il contenuto e seguire i reindirizzamenti.

4

A volte è necessario per ottenere le intestazioni HTTP, ma allo stesso tempo non si vuole restituire tali intestazioni. **

Questo scheletro si prende cura di biscotti e HTTP redirect utilizzando la ricorsione.L'idea principale qui è per evitare le intestazioni HTTP di ritorno al codice cliente.

È possibile creare una classe di arricciatura molto forte su di esso. Aggiungere 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]); 
    } 

} 
-3

È possibile utilizzare:

$redirectURL = curl_getinfo($ch,CURLINFO_REDIRECT_URL); 
14

Aggiungi questa linea ad arricciarsi inizializzazione

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 

e utilizzare getinfo prima 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é svela anche più reindirizzamenti. –

+0

Ricorda: (ok, duh) i dati POST non verranno ripresentati dopo un reindirizzamento. Nel mio caso questo è successo e mi sono sentito stupido in seguito perché: basta usare l'url appropriato ed è corretto. – twicejr

Problemi correlati