是否有任何方法来获得头部和主体的cURL请求使用PHP?我发现这个选项:
curl_setopt($ch, CURLOPT_HEADER, true);
会返回body和header,但之后我需要解析它来得到body。有没有办法以更可用(和更安全)的方式同时获得两者?
注意,对于“单个请求”,我的意思是避免在GET/POST之前发出HEAD请求。
是否有任何方法来获得头部和主体的cURL请求使用PHP?我发现这个选项:
curl_setopt($ch, CURLOPT_HEADER, true);
会返回body和header,但之后我需要解析它来得到body。有没有办法以更可用(和更安全)的方式同时获得两者?
注意,对于“单个请求”,我的意思是避免在GET/POST之前发出HEAD请求。
当前回答
这里的许多答案的问题是“\r\n\r\n”可以合法地出现在html的主体中,因此您不能确保正确地分割了头文件。
在调用curl_exec时单独存储标头的唯一方法似乎是使用回调,就像上面https://stackoverflow.com/a/25118032/3326494中建议的那样
然后,为了(可靠地)获得请求的主体,您需要将Content-Length报头的值作为负起始值传递给substr()。
其他回答
Curl有一个内置的选项,叫做CURLOPT_HEADERFUNCTION。此选项的值必须为回调函数的名称。Curl将逐行将标题(而且仅是标题!)传递给这个回调函数(因此该函数将对每个标题行调用,从标题部分的顶部开始)。然后你的回调函数可以对它做任何事情(并且必须返回给定行的字节数)。下面是经过测试的工作代码:
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);
上面的工作与一切,不同的协议和代理,你不需要担心头部的大小,或设置许多不同的卷曲选项。
注:要用object方法处理标题行,请这样做:
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($object, 'methodName'))
返回带有引用参数的响应头:
<?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;
}
?>
以防你不能/不使用CURLOPT_HEADERFUNCTION或其他解决方案;
$nextCheck = function($body) {
return ($body && strpos($body, 'HTTP/') === 0);
};
[$headers, $body] = explode("\r\n\r\n", $result, 2);
if ($nextCheck($body)) {
do {
[$headers, $body] = explode("\r\n\r\n", $body, 2);
} while ($nextCheck($body));
}
PHP文档注释中发布了一个解决方案:http://www.php.net/manual/en/function.curl-exec.php#80442
代码示例:
$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);
警告:正如下面的评论所指出的,当与代理服务器一起使用或在处理某些类型的重定向时,这可能不可靠。@Geoffrey的回答可能会更可靠地处理这些问题。
如果你正在使用GET,试试这个:
$curl = curl_init($url);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Cache-Control: no-cache"
),
));
$response = curl_exec($curl);
curl_close($curl);