Debugging cURL Requests In PHP

Introduction

cURL is a great library and tool. Quite often we'll use it to interact and fetch data from third-party API's. However, sometimes debugging requests made with cURL, specifically from a PHP application, can be tricky.

Let's say you have an integration with a third-party API and the service becomes unstable. Some requests respond as expected, while others do not. How can we determine where the code is failing?

Use Logs, Not Exceptions

Just recently, we ran into a situation where one of our cURL integrations was failing. In production environments we capture and log all exceptions using an app called Sentry. Unfortunately, in this particular situation, the exception output did not reveal very much about what was happening with our cURL requests.

To get detailed information we needed to save detailed information to a log file. This required a few additions and updates to our code.

Using Output Buffer

We start by turning on the PHP output buffer (OB) and strting the output stream. This allows us to write verbose information from cURL to the output buffer. We must do this before starting the cURL handler.

ob_start();  
$out = fopen('php://output', 'w');


Then we needed to turn on verbose output information and define the output stream.

$curl = curl_init();
curl_setopt($curl, CURLOPT_VERBOSE, true);  
curl_setopt($curl, CURLOPT_STDERR, $out);  


After the curl_exec() call you can close the stream and fetch the information from the output buffer. To correctly capture all the information from cURL you must do it in this order - first close the stream and then get the contents.

fclose($out);  
$debug = ob_get_clean();


Now the $debug variable will hold a string containing data like this:

* Hostname was NOT found in DNS cache
*   Trying 23.21.53.220...
* Connected to requestb.in (23.21.53.220) port 80 (#0)
> POST /zn36z0zn HTTP/1.1
Host: requestb.in  
Accept: application/json  
Content-Length: 9  
Content-Type: application/x-www-form-urlencoded

* upload completely sent off: 9 out of 9 bytes
< HTTP/1.1 200 OK  
< Connection: keep-alive  
* Server gunicorn/19.3.0 is not blacklisted
< Server: gunicorn/19.3.0  
< Date: Fri, 18 Sep 2015 23:42:28 GMT  
< Content-Type: text/html; charset=utf-8  
< Content-Length: 2  
< Sponsored-By: https://www.runscope.com  
< Via: 1.1 vegur  
<  
* Connection #0 to host requestb.in left intact


Optionally, you can append the response body to the $debug variable. We did that to see what the service was returning when a unexpected error occurred.

We hope you found this article helpful. Please leave a comment below if you have any questions!