2010-08-19 15 views
121

Estoy tratando de hacer que Curl siga una redirección pero no puedo hacer que funcione correctamente. Tengo una cadena que quiero enviar como un parámetro GET a un servidor y obtengo la URL resultante.¿Cómo puedo saber dónde se me redirigirá utilizando cURL?

Ejemplo:

String = Kobold alimañas
url = www.wowhead.com/search?q=Kobold+Worker

Si usted va a ese URL se lo redirigirá a "www.wowhead.com/npc=257". Quiero que Curl devuelva esta URL a mi código PHP para que pueda extraer el "npc = 257" y usarlo.

código actual:

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

Sin embargo, esto vuelve www.wowhead.com/search?q=Kobold+Worker y no www.wowhead.com/npc=257.

Sospecho que PHP está volviendo antes de que ocurra la redirección externa. ¿Cómo puedo arreglar esto?

+6

Esta es una de las principales preguntas para "curl follow redirects". Para seguir automáticamente los redireccionamientos con el comando 'curl', pase el indicador' -L' o '--location'. P.ej. 'curl -L http: // example.com /' –

Respuesta

214

Para hacer cURL seguir una redirección, utilice:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 

Ehh ... no creo que en realidad estás ejecutando el rizo ... Prueba:

curl_exec($ch);

... después de establecer las opciones, y antes de la llamada curl_getinfo().

EDIT: Si lo que desea es averiguar dónde una página redirige a, que haría uso de los consejos here, y sólo tiene que utilizar Curl para agarrar las cabeceras y extraer la cabecera Location: de ellos:

$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

Esto hace que php siga la redirección. No quiero seguir el redireccionamiento, solo quiero saber la URL de la página redirigida. –

+8

Oh, entonces ¿realmente no quieres buscar la página? Solo busca la ubicación? En ese caso, sugeriría la táctica utilizada aquí: http://zzz.rezo.net/HowTo-Expand-Short-URLs.html - básicamente solo toma el encabezado de la página que redirige y toma la ubicación: encabezado de ella. De todos modos, sin embargo, todavía necesita hacer el exec() para Curl para realmente _hacer_ cualquier cosa ... –

+4

Gracias, esto funcionó como un encanto :) –

8

La respuesta anterior no funcionó para mí en uno de mis servidores, algo relacionado con basedir, así que rehice un poco. El siguiente código funciona en todos mis servidores.

$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

El encabezado 'Location:' no siempre sigue una redirección. También vea una pregunta que es explícita sobre esto: [curl follow location error] (http://stackoverflow.com/questions/2511410/curl-follow-location-error) – hakre

4

La respuesta elegida aquí es decente, pero su mayúsculas y minúsculas, no protege contra las relativas location: cabeceras (que algunos sitios lo hacen) o páginas que en realidad podría tener la frase Location: en su contenido ... (que Zillow actualmente lo hace).

Un poco descuidada, pero un par de ediciones rápidas para hacer esto un poco más inteligentes son:

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

Tenga en cuenta que esto todavía va solamente 1 redirección de profundidad. Para profundizar, realmente necesitas obtener el contenido y seguir los redireccionamientos.

4

A veces se necesita para obtener las cabeceras HTTP, pero al mismo tiempo que no quieren devolver esos encabezados. **

Este esqueleto se encarga de las galletas y redirecciones HTTP utilizando la recursividad.La idea principal aquí es para evitar el retorno de los encabezados HTTP al código del cliente.

Puedes construir una clase de rizo muy fuerte sobre él. Añadir funcionalidad de correos, etc.

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

que puede utilizar:

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

añadir esta línea a rizar inizialization

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 

y utilizar getinfo antes 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

Creo que esta es la mejor solución, porque también despliega múltiples redirecciones. –

+0

Recuerde: (ok, duh) Los datos POST no se volverán a enviar después de una redirección. En mi caso, esto sucedió y después me sentí estúpido porque: solo usa la URL adecuada y está arreglado. – twicejr

Cuestiones relacionadas