¿Puede PHP cURL recuperar encabezados Y cuerpo de respuesta en una sola solicitud?
¿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.
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.
Muchas de las otras soluciones ofrecidas en este hilo no lo hacen correctamente.
- La división
\r\n\r\n
no es confiable cuandoCURLOPT_FOLLOWLOCATION
está 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
\n
para nuevas líneas (y un destinatario puede descartar el\r
terminador de línea ) . - Detectar el tamaño de los encabezados
CURLINFO_HEADER_SIZE
tampoco 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);
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'))
¿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);
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);