2010-03-24 9 views
15

Tengo este mensaje de error:la curvatura siga error de localización

CURLOPT_FOLLOWLOCATION no puede activarse cuando en safe_mode o un open_basedir se encuentra en

safe_mode está apagado en mi alojamiento web..

open_basedir es "".

¿Cómo puedo resolver esto?

+0

Puede extraer fácilmente el enlace del sitio referido: http://stackoverflow.com/a/3520085/669677 –

+0

aquí respondió: http://stackoverflow.com/a/6918742/2165415 –

Respuesta

5

El único lugar donde se imprime este mensaje de advertencia está en ext/rizo/interface.c

if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) { 
    if (Z_LVAL_PP(zvalue) != 0) { 
    php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set"); 
    RETVAL_FALSE; 
    return 1; 
    } 
} 

Como se puede ver en el caso de condición, ya sea open_basedir o safe_mode deben estar habilitadas.

+0

hay alguna manera de superar esto ? como una función de seguimiento de localización personalizada o algo similar – embedded

+4

Puede usar 'curl_getinfo ($ ch, CURLINFO_HTTP_CODE)' y si devuelve 301 o 302, busque el encabezado Location:. – VolkerK

+0

esta es la implementación de zsalab – dolmen

2

Me encontré con una situación similar hace un tiempo y encontré la solución a continuación. Si sabes generalmente dónde te redirigirán, esto podría funcionar para ti.

function curl($url, $postVars) 
{ 
    $go = curl_init($url); 
    curl_setopt ($go, CURLOPT_URL, $url); 
    curl_setopt($go, CURLOPT_VERBOSE, 1); 

    //follow on location problems 
    if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) 
    { 
     curl_setopt ($go, CURLOPT_FOLLOWLOCATION, $l); 
     $syn = curl_exec($go); 
     if(curl_error($go)) 
      return false; 
    } 
    else 
     $syn = curl_redir_exec($go, $postVars); 
    curl_close($go); 
    return $syn; 
} 

function curl_redir_exec($ch, $postVars) 
{ 
    static $curl_loops = 0; 
    static $curl_max_loops = 20; 
    if ($curl_loops++>= $curl_max_loops) 
    { 
     $curl_loops = 0; 
     return FALSE; 
    } 
    curl_setopt($ch, CURLOPT_HEADER, 1); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_POST, 1); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postVars); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 

    $data = curl_exec($ch); 
    if(curl_error($ch)) 
     return false; 
    list($header, $data) = explode("\n\r", $data, 2); 
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 

    $redirect_page = "[0-9]*.html"; 
    $base_redirect = "http://example.com/"; 

    if ($http_code == 301 || $http_code == 302) 
    { 
     $matches = array(); 
     $pregs = eregi($redirect_page, $data, $matches); 
     $new_url = $base_redirect . $matches[0]; 
     if (!$new_url) 
     { 
      //couldn't process the url to redirect to 
      $curl_loops = 0; 
      return $data; 
     } 
     curl_setopt($ch, CURLOPT_URL, $new_url); 

     return curl_redir_exec($ch, $postVars); 
    } 
    else 
    { 
     $curl_loops=0; 
     return $data; 
    } 
} 
1

Nunca probado en un entorno real, pero tiene una mayor transparencia con curl_exec (no hay problema con las opciones de encabezado y returntransfer).

function curl_exec_follow(/*resource*/ $ch, /*int*/ $maxredirect = 5) { 
    if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { 
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
    } else { 
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); 
     $newurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); 

     $rch = curl_copy_handle($ch); 
     curl_setopt($rch, CURLOPT_HEADER, true); 
     curl_setopt($rch, CURLOPT_NOBODY, true); 
     curl_setopt($rch, CURLOPT_RETURNTRANSFER, true); 
     do { 
      curl_setopt($rch, CURLOPT_URL, $newurl); 
      $header = curl_exec($rch); 
      if (curl_errno($rch)) { 
       $code = 0; 
      } else { 
       $code = curl_getinfo($rch, CURLINFO_HTTP_CODE); 
       if ($code == 301 || $code == 302) { 
        preg_match('/Location:(.*?)\n/', $header, $matches); 
        $newurl = trim(array_pop($matches)); 
       } else { 
        $code = 0; 
       } 
      } 
     } while ($code && $maxredirect--); 
     curl_close($rch); 
     curl_setopt($ch, CURLOPT_URL, $newurl); 
    } 
    return curl_exec($ch); 
} 
+0

Esta implementación tiene dos problemas: 1. si se produce un error, se perderá; 2. la solicitud de la URL final se realiza dos veces (una solo para encabezados, una llena) – dolmen

+0

'ini_get ('safe_mode' == 'Off')' Typo (los paréntesis deben incluir 'safe_mode', y no funcionará en todas partes) – Ruben

13

La solución consiste en implementar la redirección en el código PHP.

Aquí está mi propia implementación. Tiene dos limitaciones conocidas:

  1. que obligará CURLOPT_RETURNTRANSFER
  2. Es incompatible con CURLOPT_HEADERFUNCTION

El código:

function curl_exec_follow(/*resource*/ &$ch, /*int*/ $redirects = 20, /*bool*/ $curlopt_header = false) { 
    if ((!ini_get('open_basedir') && !ini_get('safe_mode')) || $redirects < 1) { 
     curl_setopt($ch, CURLOPT_HEADER, $curlopt_header); 
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $redirects > 0); 
     curl_setopt($ch, CURLOPT_MAXREDIRS, $redirects); 
     return curl_exec($ch); 
    } else { 
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); 
     curl_setopt($ch, CURLOPT_HEADER, true); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
     curl_setopt($ch, CURLOPT_FORBID_REUSE, false); 

     do { 
      $data = curl_exec($ch); 
      if (curl_errno($ch)) 
       break; 
      $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
      if ($code != 301 && $code != 302) 
       break; 
      $header_start = strpos($data, "\r\n")+2; 
      $headers = substr($data, $header_start, strpos($data, "\r\n\r\n", $header_start)+2-$header_start); 
      if (!preg_match("!\r\n(?:Location|URI): *(.*?) *\r\n!", $headers, $matches)) 
       break; 
      curl_setopt($ch, CURLOPT_URL, $matches[1]); 
     } while (--$redirects); 
     if (!$redirects) 
      trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING); 
     if (!$curlopt_header) 
      $data = substr($data, strpos($data, "\r\n\r\n")+4); 
     return $data; 
    } 
} 
+3

En mi caso, necesitaba agregar '&& $ code! = 303' (Ver Otro) a la condición if en do-loop para replicar mi comportamiento' CURLOPT_FOLLOWLOCATION = true'. – Ruben

+0

Publicación de blog relacionada [cURL: siga las ubicaciones con safe_mode enabled o open_basedir establecido (31 Mar 2012 por Slopjong)] (http://slopjong.de/2012/03/31/curl-follow-locations-with-safe_mode-enabled -or-open_basedir-set /) - tampoco es perfecto, pero puede ser de ayuda si alguien quiere revisar los códigos. – hakre

0

Si ya tiene una instancia $curl ya configurado y solo quiere simular curl_exec con FOLLOWLOCATION habilitada, puede usar este:

function curl_follow_exec($curl, $url = null) 
{ 
    curl_setopt($curl, CURLOPT_HEADER, true); 
    if (!is_null($url)) 
    { 
     $opts = array (
      CURLOPT_URL => $url, 
      CURLOPT_POST => false, 
      CURLOPT_PUT => false, 
     ); 
     curl_setopt_array($curl, $opts); 
    } 
    $data = curl_exec($curl); 
    $status = curl_getinfo($curl); 
    $arr = explode("\r\n\r\n", $data); 
    while (strpos(reset($arr), 'HTTP/1.1 100 Continue') !== false) 
    { 
     array_shift($arr); 
    } 
    $header = $arr[0]; 
    $body = implode("\r\n", array_slice($arr, 1)); 
    if ($status['http_code'] == 301 || $status['http_code'] == 302) 
    { 
     $matches = array(); 
     preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches); 
     $url = trim(str_replace($matches[1], "", $matches[0])); 
     return curl_follow_exec($curl, $url); 
    } 
    return $body; 
} 

Nota: no proporcione una URL al llamar a esta función si ya ha especificado la opción, solo se utiliza con fines recursivos.

Inspiré este código de la respuesta aceptada y agregué algunas cosas para administrar varios encabezados.

Esta función es como un feo hack para ie6: si puedes, cambia tu alojamiento :-).

1

Sólo una nota:

Todas las respuestas con código aquí analizar manualmente los encabezados de una solicitud de rizo para encontrar un encabezado Location:.

Sin embargo, desde PHP 5.3.7, hay una opción CURLINFO_REDIRECT_URL que puede usar con curl_getinfo(). No es necesario hacer solicitudes dos veces, no es necesario habilitar los encabezados si no los quiere, no hay necesidad de expresiones regulares.