¿Puede PHP cURL recuperar encabezados Y cuerpo de respuesta en una sola solicitud?

Resuelto gremo asked hace 54 años • 16 respuestas

¿Hay alguna manera de obtener los encabezados y el cuerpo de una solicitud cURL usando PHP? Encontré que esta opción:

curl_setopt($ch, CURLOPT_HEADER, true);

va a devolver el cuerpo más los encabezados , pero luego necesito analizarlo para obtener el cuerpo. ¿Hay alguna manera de obtener ambos de una manera más utilizable (y segura)?

Tenga en cuenta que por "solicitud única" me refiero a evitar emitir una solicitud HEAD antes de GET/POST.

gremo avatar Jan 01 '70 08:01 gremo
Aceptado

Una solución a esto se publicó en los comentarios de la documentación de PHP: http://www.php.net/manual/en/function.curl-exec.php#80442

Ejemplo de código:

$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
// ...

$response = curl_exec($ch);

// Then, after your curl_exec call:
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

Advertencia: como se indica en los comentarios a continuación, es posible que esto no sea confiable cuando se usa con servidores proxy o cuando se manejan ciertos tipos de redireccionamientos. La respuesta de @Geoffrey puede manejarlos de manera más confiable.

iblue avatar Feb 07 '2012 20:02 iblue

Muchas de las otras soluciones ofrecidas en este hilo no lo hacen correctamente.

  • La división \r\n\r\nno es confiable cuando CURLOPT_FOLLOWLOCATIONestá activado o cuando el servidor responde con un código 100 RFC-7231 , MDN .
  • No todos los servidores cumplen con los estándares y transmiten solo preguntas y respuestas \npara nuevas líneas (y un destinatario puede descartar el \rterminador de línea ) .
  • Detectar el tamaño de los encabezados CURLINFO_HEADER_SIZEtampoco siempre es confiable, especialmente cuando se usan proxies Curl-1204 o en algunos de los mismos escenarios de redireccionamiento.

El método más correcto es utilizar CURLOPT_HEADERFUNCTION.

Aquí hay un método muy limpio para realizar esto usando cierres de PHP. También convierte todos los encabezados a minúsculas para un manejo coherente entre servidores y versiones HTTP.

Esta versión conservará encabezados duplicados.

Esto cumple con RFC822 y RFC2616, no utilice las mb_funciones de cadena (y similares), no solo es incorrecto sino incluso un problema de seguridad RFC-7230 .

$ch = curl_init();
$headers = [];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
  function($curl, $header) use (&$headers)
  {
    $len = strlen($header);
    $header = explode(':', $header, 2);
    if (count($header) < 2) // ignore invalid headers
      return $len;

    $headers[strtolower(trim($header[0]))][] = trim($header[1]);
    
    return $len;
  }
);

$data = curl_exec($ch);
print_r($headers);
Geoffrey avatar Dec 14 '2016 05:12 Geoffrey

Curl tiene una opción integrada para esto, llamada CURLOPT_HEADERFUNCTION. El valor de esta opción debe ser el nombre de una función de devolución de llamada. Curl pasará el encabezado (¡y solo el encabezado!) a esta función de devolución de llamada, línea por línea (por lo que se llamará a la función para cada línea del encabezado, comenzando desde la parte superior de la sección del encabezado). Su función de devolución de llamada puede hacer cualquier cosa con ella (y debe devolver el número de bytes de la línea dada). Aquí hay un código de trabajo probado:

function HandleHeaderLine( $curl, $header_line ) {
    echo "<br>YEAH: ".$header_line; // or do whatever
    return strlen($header_line);
}


$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.google.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "HandleHeaderLine");
$body = curl_exec($ch); 

Lo anterior funciona con todo, también con diferentes protocolos y servidores proxy, y no necesita preocuparse por el tamaño del encabezado ni configurar muchas opciones de curl diferentes.

PD: para manejar las líneas de encabezado con un método de objeto, haga esto:

curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($object, 'methodName'))
Skacc avatar Aug 04 '2014 11:08 Skacc

¿Es esto lo que estás buscando?

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
$response = curl_exec($ch); 
list($header, $body) = explode("\r\n\r\n", $response, 2);
user1031143 avatar Feb 07 '2012 20:02 user1031143

Si desea específicamente el Content-Type, hay una opción cURL especial para recuperarlo:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
pr1001 avatar Mar 24 '2014 21:03 pr1001