headers - php curl-- header
¿Puede PHP cURL recuperar los encabezados de respuesta Y el cuerpo en una sola solicitud? (12)
¿Hay alguna forma de obtener los encabezados y el cuerpo para una solicitud de CURL utilizando 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 para "solicitud única" me refiero a evitar emitir una solicitud HEAD antes de GET / POST.
Curl tiene una opción incorporada 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 de 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, diferentes protocolos y proxies también, y no tiene que preocuparse por el tamaño del encabezado, o configurar muchas opciones de rizo 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''))
Devolver encabezados de respuesta con un parámetro de referencia:
<?php
$data=array(''device_token''=>''5641c5b10751c49c07ceb4'',
''content''=>''测试测试test''
);
$rtn=curl_to_host(''POST'', ''http://test.com/send_by_device_token'', array(), $data, $resp_headers);
echo $rtn;
var_export($resp_headers);
function curl_to_host($method, $url, $headers, $data, &$resp_headers)
{$ch=curl_init($url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $GLOBALS[''POST_TO_HOST.LINE_TIMEOUT'']?$GLOBALS[''POST_TO_HOST.LINE_TIMEOUT'']:5);
curl_setopt($ch, CURLOPT_TIMEOUT, $GLOBALS[''POST_TO_HOST.TOTAL_TIMEOUT'']?$GLOBALS[''POST_TO_HOST.TOTAL_TIMEOUT'']:20);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, 1);
if ($method==''POST'')
{curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
}
foreach ($headers as $k=>$v)
{$headers[$k]=str_replace('' '', ''-'', ucwords(strtolower(str_replace(''_'', '' '', $k)))).'': ''.$v;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$rtn=curl_exec($ch);
curl_close($ch);
$rtn=explode("/r/n/r/nHTTP/", $rtn, 2); //to deal with "HTTP/1.1 100 Continue/r/n/r/nHTTP/1.1 200 OK.../r/n/r/n..." header
$rtn=(count($rtn)>1 ? ''HTTP/'' : '''').array_pop($rtn);
list($str_resp_headers, $rtn)=explode("/r/n/r/n", $rtn, 2);
$str_resp_headers=explode("/r/n", $str_resp_headers);
array_shift($str_resp_headers); //get rid of "HTTP/1.1 200 OK"
$resp_headers=array();
foreach ($str_resp_headers as $k=>$v)
{$v=explode('': '', $v, 2);
$resp_headers[$v[0]]=$v[1];
}
return $rtn;
}
?>
El problema con muchas respuestas aquí es que "/r/n/r/n"
puede aparecer legítimamente en el cuerpo del html, por lo que no puede estar seguro de que está dividiendo los encabezados correctamente.
Parece que la única forma de almacenar los encabezados por separado con una llamada a curl_exec
es usar una devolución de llamada como se sugiere anteriormente en https://.com/a/25118032/3326494
Y luego, para obtener (de manera confiable) solo el cuerpo de la solicitud, necesitaría pasar el valor del encabezado Content-Length
a substr()
como un valor de inicio negativo.
Mi camino es
$response = curl_exec($ch);
$x = explode("/r/n/r/n", $v, 3);
$header=http_parse_headers($x[0]);
if ($header=[''Response Code'']==100){ //use the other "header"
$header=http_parse_headers($x[1]);
$body=$x[2];
}else{
$body=$x[1];
}
Si es necesario, aplique un bucle for y elimine el límite de explosión.
Muchas de las otras soluciones que se ofrecen en este hilo no lo hacen correctamente.
- La división en
/r/n/r/n
no es confiable cuandoCURLOPT_FOLLOWLOCATION
estáCURLOPT_FOLLOWLOCATION
o cuando el servidor responde con un código 100. - No todos los servidores cumplen con los estándares y transmiten solo un
/n
para nuevas líneas. - La detección del tamaño de los encabezados a través de
CURLINFO_HEADER_SIZE
tampoco es siempre confiable, especialmente cuando se usan proxies o en algunos de los mismos escenarios de redirección.
El método más correcto es usar CURLOPT_HEADERFUNCTION
.
Aquí hay un método muy limpio de realizar esto utilizando cierres de PHP. También convierte todos los encabezados a minúsculas para un manejo consistente entre servidores y versiones HTTP.
Esta versión conservará los encabezados duplicados.
Esto cumple con RFC822 y RFC2616, no sugiera ediciones para hacer uso de las mb_
cadena mb_
, ¡es incorrecto!
$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;
$name = strtolower(trim($header[0]));
if (!array_key_exists($name, $headers))
$headers[$name] = [trim($header[1])];
else
$headers[$name][] = trim($header[1]);
return $len;
}
);
$data = curl_exec($ch);
print_r($headers);
Si desea específicamente el tipo de Content-Type
, hay una opción especial de cURL para recuperarlo:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
Si realmente no necesitas usar rizo;
$body = file_get_contents(''http://example.com'');
var_export($http_response_header);
var_export($body);
Que salidas
array (
0 => ''HTTP/1.0 200 OK'',
1 => ''Accept-Ranges: bytes'',
2 => ''Cache-Control: max-age=604800'',
3 => ''Content-Type: text/html'',
4 => ''Date: Tue, 24 Feb 2015 20:37:13 GMT'',
5 => ''Etag: "359670651"'',
6 => ''Expires: Tue, 03 Mar 2015 20:37:13 GMT'',
7 => ''Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT'',
8 => ''Server: ECS (cpm/F9D5)'',
9 => ''X-Cache: HIT'',
10 => ''x-ec-custom-error: 1'',
11 => ''Content-Length: 1270'',
12 => ''Connection: close'',
)''<!doctype html>
<html>
<head>
<title>Example Domain</title>...
Ver http://php.net/manual/en/reserved.variables.httpresponseheader.php
Solo configura las opciones:
CURLOPT_HEADER, 0
CURLOPT_RETURNTRANSFER, 1
y use curl_getinfo con CURLINFO_HTTP_CODE (o sin opt param y tendrá una matriz asociativa con toda la información que desee)
Tenga cuidado cuando necesite las últimas cosas que regresó del servidor. Este código puede romper su expectativa mientras espera encabezados y cuerpo reales (últimos): list($headers, $body) = explode("/r/n/r/n", $result, 2);
Esta es una forma sencilla de obtener encabezados finales y partes del cuerpo;
$result = explode("/r/n/r/n", $result);
// drop redirect etc. headers
while (count($result) > 2) {
array_shift($result);
}
// split headers / body parts
@ list($headers, $body) = $result;
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_VERBOSE, 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, esto puede no ser confiable cuando se usa con servidores proxy o cuando se manejan ciertos tipos de redirecciones. La respuesta de @ Geoffrey puede manejar esto de manera más confiable.
es esto lo que estas buscando?
curl_setopt($ch, CURLOPT_HTTPHEADER, array(''Expect:''));
$response = curl_exec($ch);
list($header, $body) = explode("/r/n/r/n", $response, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$parts = explode("/r/n/r/nHTTP/", $response);
$parts = (count($parts) > 1 ? ''HTTP/'' : '''').array_pop($parts);
list($headers, $body) = explode("/r/n/r/n", $parts, 2);
Funciona con HTTP/1.1 100 Continue
antes que otros encabezados.
Si necesita trabajar con servidores con errores que envían solo LF en lugar de CRLF como saltos de línea, puede usar preg_split
siguiente manera:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$parts = preg_split("@/r?/n/r?/nHTTP/@u", $response);
$parts = (count($parts) > 1 ? ''HTTP/'' : '''').array_pop($parts);
list($headers, $body) = preg_split("@/r?/n/r?/n@u", $parts, 2);