PHP cURL 可以在单个请求中检索响应标头和正文吗?

2022-08-30 05:58:21

有没有办法使用PHP获取cURL请求的标头和正文?我发现这个选项:

curl_setopt($ch, CURLOPT_HEADER, true);

将返回正文加标头,但随后我需要解析它以获取正文。有没有办法以更可用(和安全)的方式获得两者?

请注意,对于“单个请求”,我的意思是避免在GET / POST之前发出HEAD请求。


答案 1

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的答案可能会更可靠地处理这些问题。


答案 2

此线程提供的许多其他解决方案正确执行此操作。

  • 当 打开 或 服务器使用 100 代码RFC-7231MDN 响应时,拆分是不可靠的。\r\n\r\nCURLOPT_FOLLOWLOCATION
  • 并非所有服务器都符合标准,并且仅传输新线路(收件人可能会丢弃线路终结器中的)问答\n\r
  • 通过检测标头的大小也并不总是可靠的,特别是当使用代理 Curl-1204 或在某些相同的重定向方案中时。CURLINFO_HEADER_SIZE

最正确的方法是使用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);

推荐