How to parse response headers in PHP?
Short answer if you have pecl_http: http://php.net/manual/it/function.explode.php
Slightly longer answer:
$header = "...";
$parsed = array_map(function($x) { return array_map("trim", explode(":", $x, 2)); }, array_filter(array_map("trim", explode("\n", $header))));
I ended up with this solution which uses regex to find all the keys and values in the header combined with some array mutation from https://stackoverflow.com/a/43004994/271351 to get the regex matches into an associative array. This isn't 100% appropriate for the problem asked here since it takes in a string, but joining an array of strings to get a single string would work as a precursor to this. My case had to deal with raw headers, thus this solution.
preg_match_all('/^([^:\n]*): ?(.*)$/m', $header, $headers, PREG_SET_ORDER);
$headers = array_merge(...array_map(function ($set) {
return array($set[1] => trim($set[2]));
}, $headers));
This yields an associative array of the headers. If the first line of the headers is included as input (e.g. GET / HTTP/1.1
), this will ignore it for the output.
You'll need to iterate the array and check stripos()
to find the header you're looking for. In most cases, you then explode()
on :
(limiting to 2 resultant parts), but the HTTP response code will require you to explode on the spaces.
// Get any header except the HTTP response...
function getResponseHeader($header, $response) {
foreach ($response as $key => $r) {
// Match the header name up to ':', compare lower case
if (stripos($r, $header . ':') === 0) {
list($headername, $headervalue) = explode(":", $r, 2);
return trim($headervalue);
}
}
}
// example:
echo getResponseHeader("Content-Type");
// text/html; charset=utf-8
// Get the HTTP response code
foreach ($response as $key => $r) {
if (stripos($r, 'HTTP/') === 0) {
list(,$code, $status) = explode(' ', $r, 3);
echo "Code: $code, Status: $status";
break;
}
}
It seems that the only header withou a :
is the HTTP version and status.
Do an array_shift
to extract that, iterate through the others creating an array like so:
$parsedHeaders = array();
foreach ($headers as $header) {
if (! preg_match('/^([^:]+):(.*)$/', $header, $output)) continue;
$parsedArray[$output[1]] = $output[2];
}
ps: untested.
— edit —
enjoy ;)
/**
* Parse a set of HTTP headers
*
* @param array The php headers to be parsed
* @param [string] The name of the header to be retrieved
* @return A header value if a header is passed;
* An array with all the headers otherwise
*/
function parseHeaders(array $headers, $header = null)
{
$output = array();
if ('HTTP' === substr($headers[0], 0, 4)) {
list(, $output['status'], $output['status_text']) = explode(' ', $headers[0]);
unset($headers[0]);
}
foreach ($headers as $v) {
$h = preg_split('/:\s*/', $v);
$output[strtolower($h[0])] = $h[1];
}
if (null !== $header) {
if (isset($output[strtolower($header)])) {
return $output[strtolower($header)];
}
return;
}
return $output;
}