是否有任何方法来获得头部和主体的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请求。
当前回答
这个线程提供的许多其他解决方案都没有正确地做到这一点。
当CURLOPT_FOLLOWLOCATION打开或服务器响应100代码RFC-7231, MDN时,在\r\n\r\n上的分裂是不可靠的。 并不是所有的服务器都符合标准,对新行只传输\n(收件人可能会丢弃行结束符中的\r)问答。 通过CURLINFO_HEADER_SIZE检测报头的大小也并不总是可靠的,特别是当代理使用Curl-1204或在某些相同的重定向场景中。
最正确的方法是使用CURLOPT_HEADERFUNCTION。
下面是使用PHP闭包执行此操作的一种非常简洁的方法。它还将所有头部转换为小写,以便跨服务器和HTTP版本进行一致的处理。
这个版本将保留重复的头文件
这符合RFC822和RFC2616,请不要使用mb_(和类似的)字符串函数,这不仅是不正确的,甚至是一个安全问题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);
其他回答
如果你正在使用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);
以下是我对这场辩论的看法……这将返回一个单独的数组,其中分隔了数据并列出了标题。这是基于CURL将返回一个头数据块[空行]数据
curl_setopt($ch, CURLOPT_HEADER, 1); // we need this to get headers back
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, true);
// $output contains the output string
$output = curl_exec($ch);
$lines = explode("\n",$output);
$out = array();
$headers = true;
foreach ($lines as $l){
$l = trim($l);
if ($headers && !empty($l)){
if (strpos($l,'HTTP') !== false){
$p = explode(' ',$l);
$out['Headers']['Status'] = trim($p[1]);
} else {
$p = explode(':',$l);
$out['Headers'][$p[0]] = trim($p[1]);
}
} elseif (!empty($l)) {
$out['Data'] = $l;
}
if (empty($l)){
$headers = false;
}
}
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'))
我的方法是
$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];
}
如果需要,应用for循环并移除爆炸限制。
如果你不需要使用curl;
$body = file_get_contents('http://example.com');
var_export($http_response_header);
var_export($body);
的输出
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>...
参见http://php.net/manual/en/reserved.variables.httpresponseheader.php