tl;dr I wrote a simple PHP script to test and use cURL while working with APIs.
curl is a command line tool and library to transfer
data with many different types of servers with many different types of protocols.
The most basic curl request is done with curl example.com
which triggers
a HTTP
request of method GET
to URL http://example.com
and returns the
server response in plain text.
PHP includes a module called cURL which uses the curl library to make custom HTTP requests. Therefore, it is widely used to share data between websites, for example to POST data to a service or request data from an API.
Whenever I set up an API with PHP I need a simple way to test that cURL works as expected on the system. I wrote a simple script, which tests whether cURL is installed on the local system and is able to retrieve data from a given URL. A modified version of the script can be shared with collegues or clients easily as has no further dependencies. Which makes it the perfect tool to quickly debug API connections on different enviroments.
<?php
/**
* Simple cURL request script
*
* Test if cURL is available, send request, print response
*
* php curl.php
*/
if(!function_exists('curl_init')) {
die('cURL not available!');
}
$curl = curl_init();
// or use https://httpbin.org/ for testing purposes
curl_setopt($curl, CURLOPT_URL, 'https://my-own-domain.example.com/api.php');
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
//// Require fresh connection
//curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
//// Send POST request instead of GET and transfer data
//$postData = array(
// 'name' => 'John Doe',
// 'submit' => '1'
//);
//curl_setopt($curl, CURLOPT_POST, true);
//curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
//// Use a different request method
//curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
//// If the target does not accept custom HTTP methods
//// then use a regular POST request and a custom header variable
//curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT'));
//// Note: PHP only converts data of GET queries and POST form requests into
//// convenient superglobals (»$_GET« & »$_POST«) - To read the incoming
//// cURL request data you need to access PHPs input stream instead
//// using »parse_str(file_get_contents('php://input'), $_INPUT);«
//// Send JSON body via POST request
//$postData = array(
// 'name' => 'John Doe',
// 'submit' => '1'
//);
//curl_setopt($curl, CURLOPT_POST, true);
//curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData));
//// Set headers to send JSON to target and expect JSON as answer
//curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept:application/json'));
//// As said above, the target script needs to read `php://input`, not `$_POST`!
//// Timeout in seconds
//curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
//curl_setopt($curl, CURLOPT_TIMEOUT, 10);
//// Dont verify SSL certificate (eg. self-signed cert in testsystem)
//curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
//curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$output = curl_exec($curl);
if ($output === FALSE) {
echo 'An error has occurred: ' . curl_error($curl) . PHP_EOL;
}
else {
echo $output;
}
I've saved this script in a Gist and update it from time to time.
To debug the request I always have a minimal script around as well.
<?php
/**
* Simple request response script
*
* Point you cURL request to this script to see all incoming data
*/
echo '*API*'. PHP_EOL;
echo 'Request Time: ' . time() . PHP_EOL;
echo 'Request Method: ' . print_r($_SERVER['REQUEST_METHOD'], true) . PHP_EOL;
if(FALSE === empty($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
echo 'Request Header Method: ' . print_r($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'], true) . PHP_EOL;
}
echo 'Server Data: ' . print_r($_SERVER, true) . PHP_EOL;
echo 'Request Files: ' . print_r($_FILES, true) . PHP_EOL;
echo 'Request Data: ' . PHP_EOL;
// …Will only work with GET query parameters & POST form parameters
echo 'Request params: ' . print_r($_REQUEST, true) . PHP_EOL;
// …Other methods like DELETE & PUT, and request body content types like JSON
// are not converted into PHP superglobals automatically! Read the input stream instead.
// Note: The input stream may be accessed once only!
parse_str(file_get_contents('php://input'), $_INPUT);
echo 'Input Stream: ' . print_r($_INPUT, true) . PHP_EOL;
As said above, in all these situations when the own app is not working as expected, I use this script instead of debugging tools in an app, to show collegues or hosters the expected output and the actual output.
Update: In a new revision of the script I have added an example to set a timout. The PHP process is open as long as the cURL request doesn't answer, so while running multiple requests this may cause a large load on your system if the remote server needs a long time to response. Terminate the request after a given amount of time to avoid this issue.
I did also add an example to not verify SSL certificates. This shouldn't be used on productive systems certainly. But it may be necessary to skip the verification when using self-signed certificates on testsystems.
Update 2: A word about best practices. As written above, this is a test script only. If you want to go ahead and integrate API requests in your app, you should use appropriate scripts. A generic and popular solution is Guzzle. A basic GET request in Guzzle looks like this:
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://example.com');
echo $response->getBody();
I wrote a blog post how to send and receive JSON data with Guzzle as well.