Consuming REST with PHP and Streams

With RESTful services becoming ever more popular as a way of sharing information between systems, and PHP still widely adopted as the language of the web, these two technologies are regular bedfellows. As always with PHP, there’s more than one way to work with a RESTful service, but a great option is to use streams. The streams interface is more elegant than PHP’s clunky cURL extension, and is always included in PHP. Best of all, this is stream handling, so if a response is very large it can be processed in bite-sized chunks. Let’s look at some examples of consuming a real REST service with PHP streams. We’ll use GitHub as an example since they have a good RESTful service, great documentation, and are widely known.

Starting Simple with a GET Request

Let’s begin by grabbing a list of the gists associated with my GitHub account (a gist is like a pastebin, if you haven’t seen one before):

12345678910111213

<?php

 

ini_set('user_agent', "PHP"); // github requires this

 

$api = 'https://api.github.com';

$url = $api . '/users/lornajane/gists';

// make the request

$response = file_get_contents($url);

 

// check we got something back before decoding

if(false !== $response) {

$gists = json_decode($response, true);

} // otherwise something went wrong

view rawget.php hosted with ❤ by GitHub

The response is an array of the publicly-visible gists on my account, each represented by an array and including information about the user that created them (me). The documentation for working with gists using GitHub’s API is here:http://developer.github.com/v3/gists/ The file_get_contents() stream wrapper is by far the easiest and quickest way to grab content from a URL in PHP. There is so much more we can do with it though!

Write Operations with Stream Contexts

All the stream functions in PHP have support for a $context argument, which allows us to send more information about the stream we’re sending. For an HTTP or HTTPS stream like the ones in these examples, that means we can set the headers, verbs and body to send with our request. To try this out, we’ll create a gist on GitHub, and do so we need to be logged in. In API terms, that means we need to identify ourself when we make the request, and since GitHub uses Oauth2, we can just send a header containing a valid access token that I acquired by following their excellentation documentation which you can find at http://developer.github.com/v3/#authentication Our next request also needs to send some body data as well as auth information; this is the content for the new gist which we’ll POST to Github. We can set the verb, the body data, and the headers we need all in the context of the stream. Take a look at this example:

123456789101112131415161718192021222324252627282930

<?php

 

include "github-creds.php"; // sets $access_token

ini_set('user_agent', "PHP"); // github requires this

 

$api = 'https://api.github.com';

$url = $api . '/gists'; // no user info because we're sending auth

 

// prepare the body data

$data = json_encode(array(

'description' => 'Inspiring Poetry',

'public' => 'true',

'files' => array(

'poem.txt' => array(

'content' => 'If I had the time, I\'d make a rhyme'

)

)

));

 

// set up the request context

$options = ["http" => [

"method" => "POST",

"header" => ["Authorization: token " . $access_token,

"Content-Type: application/json"],

"content" => $data

]];

$context = stream_context_create($options);

 

// make the request

$response = file_get_contents($url, false, $context);

view rawpost.php hosted with ❤ by GitHub

First of all I’m pulling in my access token from a separate include file (to avoid oversharing or having to revoke tokens). Then we set the URL and assemble the data we want to send. This will be different on different systems but I’m working off GitHub’s documentation for creating a gist: http://developer.github.com/v3/gists/#create-a-gist. Setting the context is probably the trickiest bit, and even then you can see the pieces clearly. Set that this should be a POST request, then give some extra headers; we set the Content-Type because we’re sending JSON in the body of this request (the GitHub API works only in JSON), and the Authorization header contains our access token so GitHub knows who we are. Finally we set the data we prepared earlier as the content for the stream. When the gist is created successfully, the response will give full information about this gist and its new URL, along with a 201 status code to tell you it was created (inspect this by checking the $http_response_header> variable). If the first code sample was run again now, we’d see a new entry appear in our list, and it’s also visible on the website: [gists.png] We can work with gists and other types of API data programmatically, and PHP is a great tool for this.

Going Beyond GET and POST

The streams solution is a more friendly interface than the more traditional PHP curl, and it’s equally powerful as we’ve seen in the examples so far. It can be used to make requests using any HTTP verb, the only requirement is that both client and server should understand it. For example, if we wanted to update the gist that we just created, then we’d make a request to GitHub using the PATCH verb. PATCH isn’t supported everywhere, but GitHub have adopted it as a great way of updating records, including partial records, and this is becoming more popular in RESTful services. Here’s an example of how we might do that using the stream context:

12345678910111213141516171819202122232425262728

<?php

 

include "github-creds.php"; // sets $access_token

ini_set('user_agent', "PHP"); // github requires this

 

$api = 'https://api.github.com';

$url = $api . '/gists/5501496'; // URL of the specific gist

 

// prepare the body data

$data = json_encode(array(

'description' => 'Rather Lame Poetry'

));

 

// set up the request context

$options = ["http" => [

"method" => "PATCH",

"header" => ["Authorization: token " . $access_token,

"Content-Type: application/json"],

"content" => $data

]];

$context = stream_context_create($options);

 

// make the request

$response = file_get_contents($url, false, $context);

 

echo $response;

print_r(json_decode($response));

print_r($http_response_header);

view rawpatch.php hosted with ❤ by GitHub

The changes are accepted by GitHub and the response contains the updated gist, in this case the script just changes the description field.

PHP and Streams

The streams extension is core to PHP and so it will always be available, making it a great choice for code that needs to be deployed to a number of platforms. The interface is simple and elegant, so as a developer it’s easy to work with while at the same time being completely configurable, allowing even the more complex kinds of requests as we saw here. Best of all, if you’re dealing with very large responses, you can handle them in segments rather than loading the entire response into memory, as well as getting all the other features of streams such as being able to filter them as needed. There are many ways to make HTTP requests from PHP but streams are definitely one of the best, combining power with flexibility.

PHP web servicesLorna Jane Mitchell is a web development consultant and trainer from Leeds in the UK, specialising in open source technologies, data-related problems, and APIs. She is also an open source project lead, regular conference speaker, prolific blogger, and author of PHP Web Services, published May 2013 by O’Reilly.

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s