Handling response headers from cURL requests in PHP

Getting the HTTP response headers with cURL in PHP is not straight forward. There is no build-in way to do this, but we can still cut out the headers from the response message, if CURLOPT_HEADER is true.

51381 views
d

By. Jacob

Edited: 2021-04-12 11:12

cURL headers, and server responses.

When a HTTP request has been received by a server, typically a response is sent back to the client, and the server response will usually consist of two parts; the Response Header and the Response Body.

The header part of the response contains all the response headers, including cookies (if any) and information about the mime type of the content. The response body contains the content, which should match the mine-type in the headers. For example, common mime-types might be text/html for HTML pages, and text/css for external StyleSheets.

To show the response headers to a given request, we can simply cut out the headers using a combination of the options and functions. A more detailed explanation of this is available in the next section of the article, for those interested.

A quick full example is included below:

$url = "https://beamtic.com/api/user-agent";

$ch = curl_init();

  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HEADER, 1);

  $response = curl_exec($ch);
  
  // Retudn headers seperatly from the Response Body
  $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  $headers = substr($response, 0, $header_size);
  $body = substr($response, $header_size);
  
curl_close($ch);

header("Content-Type:text/plain; charset=UTF-8");
echo $headers;
echo $body;

The above will output something like:

HTTP/1.1 200 OK
date: Sun, 21 Feb 2021 12:11:57 GMT
server: 0
cache-control: no-cache
expires: -1
allow: GET, HEAD
strict-transport-security: max-age=31536000; includeSubDomains
vary: Accept-Encoding
content-encoding: br
x-frame-options: SAMEORIGIN
content-length: 10252
content-type: text/html; charset=utf-8

The response code is always the first line that is returned in the response head.

Obtaining headers as key : value pairs

As discussed in the article on parsing response headers in PHP, we can also create an associative array containing key : value pairs. Since we already got the headers, we could do like this:

// Convert the $headers string to an indexed array
$headers_indexed_arr = explode("\r\n", $headers);

// Define as array before using in loop
$headers_arr = array();
// Remember the status message in a separate variable
$status_message = array_shift($headers_indexed_arr);

// Create an associative array containing the response headers
foreach ($headers_indexed_arr as $value) {
  if(false !== ($matches = explode(':', $value, 2))) {
    $headers_arr["{$matches[0]}"] = trim($matches[1]);
  }                
}

// Show that it works
header('content-type: text/plain; charset=utf-8');
print_r($headers_arr);exit();

Retrieving the response headers

There is no build-in way to only return the response headers using cURL in PHP. However, we can still "cut" them from the full response. To do this, we first determine the size of the response header, and then simply cut it from the response using the substr() function.

First, we set the CURLOPT_HEADER option true. Doing this will include the headers in the response downloaded by cURL. Next, we will need to cut out the headers.

Using this method, we can return both the body and header part of the response. However, before we can separate the components of the response, we need to get the size of the header. This can be done using curl_getinfo() with the CURLINFO_HEADER_SIZE option, as shown below:

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);

Finally, we may use the value returned by curl_getinfo() with substr() to seperate the headers from the response message.

$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);

Create an array containing each header

In order to better work with the individual headers, we should place them in an array. HTTP Headers are separated by a Carriage Return and a Line Feed, also known as CRLF (Sometimes also represented as: [CR][LF]). Knowing this, we can create an array from the raw headers using the PHP explode() function.

$headers_arr = explode("\r\n", $headers); // The separator used in the Response Header is CRLF (Aka. \r\n)
print_r($headers_arr); // Shows the content of the $headers_arr array

As you can see, we also have a couple of empty entries. To remove those, we can pass the array to the array_filter() function:

$headers_arr = array_filter($headers_arr);

Finally, we can easily work on the array in a loop.

$html = '';
foreach ($headers as &$value) {
    $html .= '<li>' . $value . '</li>';
}
$html = '<ol>' . $html . '</ol>';

Finished example:

// URL to fetch
$url = "https://beamtic.com/";

$ch = curl_init();

  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HEADER, 1);

  $response = curl_exec($ch);
  
  // Retudn headers seperatly from the Response Body
  $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  $headers = substr($response, 0, $header_size);
  $body = substr($response, $header_size);
  
curl_close($ch);

$headers = explode("\r\n", $headers); // The seperator used in the Response Header is CRLF (Aka. \r\n) 

$headers = array_filter($headers);

$html = '';
foreach ($headers as &$value) {
    $html .= '<li>' . $value . '</li>';
}
$html = '<ol>' . $html . '</ol>';

header("Content-Type:text/html; charset=UTF-8");
echo $html;

Tools:

You can use the following API endpoints for testing purposes:

https://beamtic.com/api/user-agent
https://beamtic.com/api/request-headers

Tell us what you think:

Alonso Quinones

Great walkthrough, thanks.
Maybe you could also add how to split the result into key/value - pairs, since currently each array object is one long string.
/Regards, Alonso

Timilica

Hello,
I have a big problem with cURL trying to get passed a login page.
I've used all the necessary cURL options (CURLOPT_COOKIEJAR, CURLOPT_COOKIEFILE, CURLOPT_FOLLOWLOCATION) to get cURL pass the login page but with no luck. I'm trying to pass the login on http://apps.allogalogistics.ro and get some records on another page. The login page has a redirect.

I make a POST req on the login page and I save the cookies in a cookies.txt with CURLOPT_COOKIEJAR and CURLOPT_COOKIEFILE. I see that after the POST req another GET req is initiated in the login process. I tried everything I read but all I can see from cURL is the login page with the username/password empty (not logged) even if the response is 200 OK.

Can you pls give me an advice?

Kind regards

Lawrence Kennon

This is a useful article. I encapsulated a lot of this code into a function that I am using in a lot of command line scripts on Mac for a number of purposes at work. Thanks!

EcoTechie

I was trying to only get the headers and found get_headers( $url, 1 ) to work fantastically. Adding the second option to the function gives you an associative array.
https://www.php.net/manual/en/function.get-headers.php

  1. In this Tutorial, it is shown how to redirect all HTTP requests to a index.php file using htaccess or Apache configuration files.
  2. How to create a router in PHP to handle different request types, paths, and request parameters.
  3. Tutorial on how to use proxy servers with cURL and PHP
  4. When using file_get_contents to perform HTTP requests, the server response headers is stored in a reserved variable after each successful request; we can iterate over this when we need to access individual response headers.
  5. How to effectively use variables within strings to insert bits of data where needed.

More in: PHP Tutorials