Simple URL Access with File Functions in PHP

An extremely convenient aspect of file access functions like file_get_contents() is that they understand URLs in addition to local filenames. Grabbing a remote URL and putting it into a string is just a matter of handing that URL to file_get_con tents().

Example 11-1 uses file_get_contents() to display an interesting fact from the web­site numbersapi.com about September 27th.

Example 11-1. Retrieving a URL with file_get_contents()

Did you know that <?= file_get_contents(‘http://numbersapi.com/09/27’) ?>

The Numbers API knows a lot of facts about each day, but for me the result of Example 11-1 looked like this:

Did you know that September 27th is the day in 1961 that Sierra Leone

joins the United Nations.

The http_build_query() function is useful when you need to build an API URL that includes query string parameters. Give http_build_query() an associative array of parameter names and values and it gives you back a string of key=value pairs joined by & and properly encoded—exactly what you need for a URL.

The United States Department of Agriculture has a nifty API on top of its National Nutrient Database. This NDB API is free and easy to use.

Example 11-2 uses the NDB search API to find some information about black pepper. This API returns information about each food in the database whose name matches what’s in the q query string parameter.

Example 11-2. Putting query string parameters in an API URL

$params = array(‘api_key’ => NDB_API_KEY,

  ‘q’ => ‘black pepper’,

  ‘format’ => ‘json’);

$url = “http://api.nal.usda.gov/ndb/search?” . http_build_query($params);

The $url variable in Example 11-2 is set to something like the following (the actual value depends on your API key):

http://api.nal.usda.gov/ndb/search?

api_key=j724nbefuy72n4&q=black+pepper&format=json

Each key and value in the $params array has been put together with = and &, and spe­cial characters, such as the space in black pepper, have been encoded.

Passing such a URL to file_get_contents() makes the API call. In this case, the API returns JSON, so the return value of file_get_contents() is this string:

{

“list”: {

“q”: “black pepper”,

“sr”: “27”,

“start”: 0,

“end”: 1,

“total”: 1,

“group”: “”,

“sort”: “r”,

“item”: [

{

“offset”: 0,

“group”: “Spices and Herbs”,

“name”: “Spices, pepper, black”,

“ndbno”: “02030”

}

]

}

}

Because file_get_contents() returns the response from retrieving the URL as a string, it’s a snap to pass that string to other functions that further transform it. For example, pass the API response above to json_decode() to transform the JSON into a PHP data structure you can manipulate. Example 11-3 prints out the NDB ID num­ber for each matching food item.

Example 11-3. Decoding a JSON API response

$params = array(‘api_key’ => NDB_API_KEY,

‘q’ => ‘black pepper’,

‘format’ => ‘json’);

$url = “http://api.nal.usda.gov/ndb/search?” . http_build_query($params);

$response = file_get_contents($url);

$info = json_decode($response);

foreach ($info->list->item as $item) {

print “The ndbno for {$item->name} is {$item->ndbno}.\n“;

}

The json_decode() function turns JSON objects into PHP objects and JSON arrays into PHP arrays. The top-level item in the response is an object. This is the return value from json_decode() and is assigned to $info. That object has a list property that is another object. The list object can be referred to as $info->list. That list object has an array property named item whose elements hold the details about the matching foods. So, the array that foreach() iterates over is $info->list->item. Each $item inside the foreach() loop is one object from that array. Example 11-3 prints:

The ndbno for Spices, pepper, black is 02030.

The NDB API calls made so far return JSON because of the format=json query string parameter. The API also supports specifying the response format by sending a Content-Type header. A header value of application/json tells the server to format the response as JSON.

To add headers to your HTTP request with file_get_contents(), you create a stream context. The PHP engine’s underlying mechanisms for flowing data into and out of your programs are called streams. A stream can be a local file, a remote URL, or another exotic place that produces or consumes data. The first argument to file_get_contents() is the stream’s target: the file or URL to read from or write to. Additional information about the reading or writing operation is expressed through the stream context, created by passing an associative array of the additional informa­tion to the stream_context_create() function.

Different kinds of streams support different kinds of options for their contexts. For the http stream, a header option gets a string value containing the names and values of any headers to send with the HTTP request. Example 11-4 shows how to create a stream context that includes an HTTP header and use it with file_get_contents().

Example 11-4. Sending HTTP headers with a stream context

// Just key and query term, no format specified in query string

$params = array(‘api_key’ => NDB_API_KEY,

  ‘q’ => ‘black pepper’);

$url = “http://api.nal.usda.gov/ndb/search?” . http_build_query($params);

// Options are to set a Content-Type request header

$options = array(‘header’ => ‘Content-Type: application/json’);

// Create a context for an ‘http’ stream

$context = stream_context_create(array(‘http’ => $options));

// Pass the context as the third argument to file_get_contents

print file_get_contents($url, false, $context);

In Example 11-4, the $options array contains the key/value pairs of options to set. The stream_context_create() function needs to be told which kind of stream it’s creating a context for, so its argument is an array whose key is the stream type (http) and the value is the options to set.

The second argument of file_get_contents() indicates whether the function should pay attention to the PHP engine’s include path when looking for a file. This is irrelevant with HTTP, so false is supplied for a value. The context is the third argu­ment to file_get_contents().

The context is also how you send a POST request with file_get_contents(). The method context option controls the request method, and the content context option contains any request body to send. The content must be formatted properly for the content type you specify as a header.

We can’t use the NDB API for POST, since it just tells us nutrition data via GET. It doesn’t allow us to send new data in. Example 11-5 uses file_get_contents() to send a POST request to an example URL. This request acts just like a form submission sending two form variables: name and smell.

Example 11-5. Sending a POST request with file_get_contents()

$url = ‘http://php7.example.com/post-server.php’;

// Two variables to send via POST

$form_data = array(‘name’ => ‘black pepper’,

‘smell’ => ‘good’);

// Set the method, content type, and content

$options = array(‘method’ => ‘POST’,

   ‘header’ => ‘Content-Type: application/x-www-form-urlencoded’,

   ‘content’ => http_build_query($form_data));

// Create a context for an ‘http’ stream

$context = stream_context_create(array(‘http’ => $options));

// Pass the context as the third argument to file_get_contents.

print file_get_contents($url, false, $context);

In Example 11-5, the method stream context option ensures that this is a POST request. The value you supply here is used verbatim by the PHP engine to make the request, so be sure to make it all capital letters. The value for the Content-Type header is the standard value that web browsers use for regular form data. It corresponds to data formatted like query string parameters but sent in the request body. Conveniently, this lets us use http_build_query() to construct the properly formatted request body.

In Example 11-5, as in other examples in this section, php7.exanple.com is used as a sample hostname. You must change this to a real hostname (preferably of your own web server!) to make the code work.

If you need to send a different kind of data in your POST request, just change the value of the Content-Type header and how you format the request content. For example, to send JSON, change the header option to Content-Type: application/json and change the content option to json_encode($form_data).

More information about the PHP engine’s different stream types and other supported context options is available at http://www.php.net/context.

Although the simplicity of retrieving URLs with built-in file access functions is fantastic, these functions do not make life simple if there is an error when making the request. When that happens, file_get_contents() returns false and the PHP engine generates an error message that looks like failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found. Having more control over what to do when a request is not successful is one good reason to use the cURL functions instead.

Source: Sklar David (2016), Learning PHP: A Gentle Introduction to the Web’s Most Popular Language, O’Reilly Media; 1st edition.

Leave a Reply

Your email address will not be published. Required fields are marked *