Can PHP CURL Retrieve Response Headers AND Body In A Single Request?
Answer :
One solution to this was posted in the PHP documentation comments: http://www.php.net/manual/en/function.curl-exec.php#80442
Code example:
$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);
Warning: As noted in the comments below, this may not be reliable when used with proxy servers or when handling certain types of redirects. @Geoffrey's answer may handle these more reliably.
Many of the other solutions offered this thread are not doing this correctly.
- Splitting on
\r\n\r\n
is not reliable whenCURLOPT_FOLLOWLOCATION
is on or when the server responds with a 100 code. - Not all servers are standards compliant and transmit just a
\n
for new lines. - Detecting the size of the headers via
CURLINFO_HEADER_SIZE
is also not always reliable, especially when proxies are used or in some of the same redirection scenarios.
The most correct method is using CURLOPT_HEADERFUNCTION
.
Here is a very clean method of performing this using PHP closures. It also converts all headers to lowercase for consistent handling across servers and HTTP versions.
This version will retain duplicated headers
This complies with RFC822 and RFC2616, please do not suggest edits to make use of the mb_
string functions, it is incorrect!
$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 has a built in option for this, called CURLOPT_HEADERFUNCTION. The value of this option must be the name of a callback function. Curl will pass the header (and the header only!) to this callback function, line-by-line (so the function will be called for each header line, starting from the top of the header section). Your callback function then can do anything with it (and must return the number of bytes of the given line). Here is a tested working code:
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);
The above works with everything, different protocols and proxies too, and you dont need to worry about the header size, or set lots of different curl options.
P.S.: To handle the header lines with an object method, do this:
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$object, 'methodName'))
Comments
Post a Comment