steved
steved

Reputation: 31

PHP curl - obtain response headers when error exists?

I am calling a REST service using php curl. If an error occurs (for example because I posted invalid data) the REST server returns error code 400 and provides informative application error details in the response header custom field.

However, when error 400 occurs the header is not provided in the result from curl_exec() at it returns FALSE even though setopt as been provided. Headers are seen if code returned is 2xx.

curl_setopt($curl,CURLOPT_HEADER, 1);

Is there any way to get the response headers on errors >= 400?

Upvotes: 0

Views: 1668

Answers (2)

Lee Salminen
Lee Salminen

Reputation: 880

Here's another option using the CURLOPT_HEADERFUNCTION option with a callback function:

<?php

// this holds the response headers from the curl call
$responseHeaders = array();

// this function processes the response headers from the curl call
function curlResponseHeaderCallback($ch, $headerLine) {
    global $responseHeaders;

    // trim all the whitespace on this line
    $trimmed = trim($headerLine);

    // only proceed if the string is not empty
    if(!empty($trimmed)) {
        // headers follow Key: Value format
        $split   = explode(':', $trimmed);

        // only proceed if the value of the header is not empty
        if(!empty($split[1])) {
            // $split[0] is the Key of the response header
            // $split[1] is the Value of the response header, which can also have whitespace
            $responseHeaders[$split[0]] = trim($split[1]);
        }
    }

    // who knows why, but you have to return this.
    return strlen($headerLine);
}

// get cURL resource
$ch = curl_init();

// set url
curl_setopt($ch, CURLOPT_URL, "https://httpstat.us/400");

curl_setopt($ch, CURLOPT_HEADERFUNCTION, "curlResponseHeaderCallback");

// send the request
curl_exec($ch);

// close the handle
curl_close($ch);

print_r($responseHeaders);

returns

Array
(
    [Cache-Control] => private
    [Content-Length] => 15
    [Content-Type] => text/plain; charset=utf-8
    [Server] => Microsoft-IIS/10.0
    [X-AspNetMvc-Version] => 5.1
    [Access-Control-Allow-Origin] => *
    [X-AspNet-Version] => 4.0.30319
    [X-Powered-By] => ASP.NET
    [Set-Cookie] => ARRAffinity=93fdbab9d364704de8ef77182b4d13811344b7dd1ec45d3a9682bbd6fa154ead;Path=/;HttpOnly;Domain=httpstat.us
    [Date] => Wed, 13 Nov 2019 23
)

Upvotes: 0

Lee Salminen
Lee Salminen

Reputation: 880

In the example below, I'm using https://httpstat.us/400 to simulate a HTTP 400 response code.

<?php

// create curl resource
$ch = curl_init();

// set url that responds with HTTP 400 status
curl_setopt($ch, CURLOPT_URL, "https://httpstat.us/400");

//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//enable headers
curl_setopt($ch, CURLOPT_HEADER, 1);
//get only headers
curl_setopt($ch, CURLOPT_NOBODY, 1);
// $output contains the output string
$output = curl_exec($ch);

// close curl resource to free up system resources
curl_close($ch);

$headers = [];
$output = rtrim($output);
$data = explode("\n",$output);
$headers['status'] = $data[0];
array_shift($data);

foreach($data as $part){

    //some headers will contain ":" character (Location for example), and the part after ":" will be lost, Thanks to @Emanuele
    $middle = explode(":",$part,2);

    //Supress warning message if $middle[1] does not exist, Thanks to @crayons
    if ( !isset($middle[1]) ) { $middle[1] = null; }

    $headers[trim($middle[0])] = trim($middle[1]);
}

// Print all headers as array
print_r($headers);

This returns

Array
(
    [status] => HTTP/1.1 400 Bad Request
    [Cache-Control] => private
    [Content-Length] => 15
    [Content-Type] => text/plain; charset=utf-8
    [Server] => Microsoft-IIS/10.0
    [X-AspNetMvc-Version] => 5.1
    [Access-Control-Allow-Origin] => *
    [X-AspNet-Version] => 4.0.30319
    [X-Powered-By] => ASP.NET
    [Set-Cookie] => ARRAffinity=93fdbab9d364704de8ef77182b4d13811344b7dd1ec45d3a9682bbd6fa154ead;Path=/;HttpOnly;Domain=httpstat.us
    [Date] => Wed, 13 Nov 2019 23:31:51 GMT
)

That array with all response headers matches up with what I get when I use curl from my terminal:

curl -v https://httpstat.us/400

returns

< HTTP/1.1 400 Bad Request
< Cache-Control: private
< Content-Length: 15
< Content-Type: text/plain; charset=utf-8
< Server: Microsoft-IIS/10.0
< X-AspNetMvc-Version: 5.1
< Access-Control-Allow-Origin: *
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Set-Cookie: ARRAffinity=93fdbab9d364704de8ef77182b4d13811344b7dd1ec45d3a9682bbd6fa154ead;Path=/;HttpOnly;Domain=httpstat.us
< Date: Wed, 13 Nov 2019 23:33:19 GMT

Upvotes: 1

Related Questions