Chapter 2. REST with PHP— A First Look

This chapter will introduce the basic PHP routines that could be used to work with REST. We will cover the areas related to:

  • Building a request

  • Sending the request

  • Receiving the response and processing the received response

  • How to work with HTTP verbs using an HTTP client library like CURL for sending and receiving messages

  • How to use XML parser APIs in PHP to build and process XML requests and responses

    • Build requests on client side

    • Build responses on server side

    • Process responses on client side

    • Process requests on server side

HTTP with PHP

There are multiple techniques and libraries available with PHP to deal with HTTP. In this book, our main interest would be on the mechanisms of dealing with HTTP that would help us use REST.

As mentioned in the previous chapter, if you host a PHP script with a web server that becomes a resource as per the principles of REST architectural style, then you have a service. So, when you use a web server, you have the luxury of the web server dealing with the HTTP protocol for you. You have little to worry about other than being sensitive to the elements of the protocol such as the verbs in use.

If you are implementing service clients, then you have to use some form of HTTP client library that will help you in using various HTTP verbs and other protocol elements with ease.

Let us start with the simplest cases. As briefly shown in the previous chapter, file_get_contents can be used to access a resource over the HTTP protocol.

<?php
$url = "http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto";
$result = file_get_contents($url);
echo $result;
?>

The output that we get after running the code snippet is as follows.

<?xml version="1.0" encoding="UTF-8" ?>
- <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:srch" xsi:schemaLocation="urn:yahoo:srch http://api.search.yahoo.com/WebSearchService/V1/WebSearchSpellingResponse.xsd">
<Result>apocalypto</Result>
</ResultSet>

In this sample, we are accessing the Yahoo spelling suggestion service. While using the file_get_contents method would be simple, there are a few limitations in using this function to access service. As an example, this function would always use HTTP GET method on the given URL. You have no control over the HTTP method to be used with this function. Also note that file_put_contents does not support writing to network connections, hence you would not be able to perform a PUT operation on a resource with that function. Also note that this function may not be enabled in most hosting platforms, because of safe_mode (http://www.php.net/features.safe-mode).

So we need a more feature-packed HTTP client library. As we have already seen in the last chapter, we can use the CURL PHP API (http://www.php.net/curl).

CURL

CURL is an abbreviation for "Client URL Request Library", or sometimes the recursive version "Curl URL Request Library". CURL is a powerful library because of the power of the library that it wraps, namely libcurl. The reasons for libcurl to be considered a powerful library include the fact that it currently supports the http, https, ftp, gopher, telnet, dict, file, and ldap protocols, its support for HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, and username password authentication. CURL PHP API comes with a wide array of options and features. This allows users to fine tune the requests and the way that the responses are handled.

In this section, we will explore how we can utilize CURL to use various HTTP methods that we would require to consume REST services. Note that CURL is a PHP extension. Usually it comes pre-built with the binary distributions. However, on shared Web hosting environments, libcurl might often not be available since PHP extensions are reduced to a bare minimum. And if you want to install PHP5 by building it from source distribution, CURL is not enabled by default compilation configuration. You can find more install and configuration options at http://us.php.net/manual/en/curl.setup.php.

There are four main steps when you are using CURL:

  1. Initialize CURL

  2. Set options

  3. Execute CURL

  4. Close CURL

These steps, initializing, executing, and closing are standard steps that you would use irrespective of the HTTP method that you want to use with the URL. It is the set of options that you have to change based on the HTTP method you want to use. As an example, CURLOPT_GET option would be used for HTTP GET and CURLOPT_POST would be used for HTTP POST.

Initialize:

$ch = curl_init();

Set Options:

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_GET, true);

Execute:

curl_exec($ch);

Close:

curl_close($ch);

In this example, we are using HTTP GET method. We tell CURL to use GET method by setting CURLOPT_GET option to true.

HTTP GET

It is useful to know what to expect when you are using various HTTP verbs. This is because you can always look into the sent message and verify that the correct HTTP verb was used along with parameters. As an example, have a look at the following message:

GET /WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto HTTP/1.0
Host: search.yahooapis.com:80

It shows that a GET request has been sent to search.yahooapis.com host, requesting for the resource that provides spell suggestion functionality. You can also note the fact that we are using the HTTP 1.0 protocol version here. You will find more information on how to capture the messages and verify the integrity of messages in Chapter 6, Troubleshooting Services and Clients.

Earlier in this chapter it was shown how to access the Yahoo spelling service with the file_get_contents function. The following code shows how to do the same with CURL. As you will notice, the code is a bit lengthier than the equivalent file_get_contents version. Obviously, this is the cost you have to pay in exchange of the customizability of CURL. However, you will soon realize that the increased number of lines is negligible in comparison to what you can do with CURL.

<?php
$url = "http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_GET, true);
curl_exec($ch);
curl_close($ch);
?>

The code shown above would result in a request that looks like the following. (Note that these messages were captured using a message capturing tool, explained in Chapter 6).

GET /WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto HTTP/1.0
Host: search.yahooapis.com:80

And the response:

HTTP/1.1 200 OK
Date: Sat, 17 May 2008 01:24:27 GMT
Cache-Control: private
Connection: close
Content-Type: text/xml; charset=utf-8
<?xml version="1.0" encoding="UTF-8"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:srch" xsi:schemaLocation="urn:yahoo:srch http://api.search.yahoo.com/WebSearchService/V1/WebSearchSpellingResponse.xsd">
<Result>apocalypto</Result>
</ResultSet>

When you run into trouble and want to troubleshoot to figure out what went wrong, looking into the messages to verify the verbs, parameters, HTTP headers and the message content, usually termed payload, would be very helpful. In the following sections, sample source code will be presented to demonstrate how to use CURL API for PHP to make use of various HTTP verbs.

Also, it is worth mentioning that this script would print the response from the service directly to the console, even though we are not using an echo in the script. This is because we need one more option to instruct CURL not to send the received data to the standard output. That option is named CURLOPT_RETURNTRANSFER and must be set to true to get the result of the CURL invocation as a string to a variable. When using CURL for REST clients, more often than not, you would want to capture the return value to a variable rather than printing it directly as an output, because you often would want to process the response from the service before presenting that to the user.

Here is the same client code with option CURLOPT_RETURNTRANSFER set to true. Note that unlike in the previous sample, we now have to use echo to display the returned XML response, and in order to echo we need to capture the response returned as a string from the curl_exec function. Also note that in this sample we are not looking to process the response, rather the output as it is. Later in this chapter we will discuss how to use XML parsers to process the response.

<?php
$url = "http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_GET, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
HTTP GET, CURLusing?>

HTTP POST

Most of the services on the internet that support POST or PUT operations would require some form of authentication. This is due to the sensitive nature of these operations especially when it comes to security. The service providers need to control those people who can modify resources.

Because of the complexity of some of the authentication methods in use, if we use a public service to demonstrate the POST method, it would reduce the prominence that should be given to the main subject in discussion in this section of the chapter. Hence, let us use our own service script to see how to use HTTP methods such as POST, PUT and DELETE.

Following is a simple PHP script that you can deploy with your web server and can act as our test service.

<?php
$input = file_get_contents("php://input");
file_put_contents("php://output", $input);
?>

This service script is very simple and straightforward. We just read the incoming payload and write that to the output, a very simple echo service. We will focus on the client side, making requests and processing responses, for the time being, rather than handling requests and generating responses on the server side. We shall visit the server side later. To keep things clean, let's deploy this service to a folder named rest/02 on the web server and you can name this script message_trace.php. To deploy the service, create a directory structure rest/02 in the document root directory of the server and create a PHP script message_service.php in the 02 directory. Copy the PHP script in the previous listing to the message_service.php file.

Now let's see how to write a PHP client that will POST data to this service. This client would send the payload to the service, and the service would echo that payload back. The client would capture the response and echo the response to the output. And here is code for the client.

<?php
$url = 'http://localhost/rest/02/message_trace.php';
$data = <<<XML
<text>Hello World!</text>
XML;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>

The output would be:

<text>Hello World!</text>

First, the URL where the service is located is defined. We assume that the server is the localhost, meaning that the service script is hosted on the same machine where the client is hosted.

$url = 'http://localhost/rest/02/message_trace.php';

Then the message content and the payload to be sent to the server is defined.

$data = <<<XML
<text>Hello World!</text>
XML;

Then the initialization and the setting of options for CURL are done.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Set the option to indicate that we want to make use of HTTP POST verb.

curl_setopt($ch, CURLOPT_POST, true);

Also, set the data to be posted as an option.

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

If you compare this script that POST data from a service to the earlier script where we GET data from a service, you can notice some minor differences.

  • Unlike in the GET case, we have some $data prepared to be sent to the service

  • We have used CURLOPT_POST instead of CURLOPT_GET

  • And we also have used a new option CURLOPT_POSTFIELDS

The rest of the code is similar to the GET client, since we follow the four step process for using CURL.

The semantics of this script is very simple: Prepare the data to be posted, set the HTTP method to be used to POST, set the option pointing to the data to be POSTed, send the request that is POST data, and process the response.

In the REST architectural style, POST is used to update a resource and the response might not contain any payload. However, some applications could choose to return the old resource value in the response after updating the resource with new incoming data.

HTTP PUT

As in the case of the example used to demonstrate HTTP POST method, we will use a simple demo service for demonstrating HTTP PUT method, to keep our focus on how to use CURL to make a PUT request. Here is the code for service script, and we will name this script as put.php.

<?php
$putdata = fopen("php://input", "r");
$fp = fopen("put_data_file.txt", "a");
while ($data = fread($putdata, 1024))
fwrite($fp, $data);
fclose($fp);
fclose($putdata);
?>

This simple script will open the input stream containing the PUT data as a file. A file, when read from start to end could be considered as a stream of data. A file could be opened and its data read, and that data could be considered as an input for a script. Since this mechanism provides the input as a stream of data, it is often termed as the input stream. Similarly, a file could be opened and the output be written to that file, then we call it the output stream. After reading the input stream, this script then opens another file named put_data_file.txt and places all the data PUT into that file. Lets host this service in the folder rest/02.

Note that, even though in theory we could create a new resource with HTTP PUT method with REST architectural style, most of the web servers will not allow the creation of new resources on the server due to security reasons. Since PHP is often hosted as a module of the web server, the file write privileges the PHP script has would be similar to those of the web server. Web servers discourage the Web application users by allowing them to place content into the web server host's file system, because such facilities could be misused to upload harmful scripts and compromise the host machine's security by executing those uploaded scripts.

<?php
$url = 'http://localhost/rest/02/put.php';
$fh = fopen('data.txt', 'r'),
$data = file_get_contents('data.txt'),
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($data));
curl_exec($ch);
curl_close($ch);
?>

To run the previous PHP script, create an input text file data.txt, which has some text data in the document root directory of the server.

Note that there is no output generated by this example script. This is because the script uses the functionality provided by the script that it is accessing, namely put.php, the service in this case, and there is no response message involved with this interaction. When working with services and clients, it is a common scenario to have no visible output associated with the client and server interactions. The client would trigger some business processing on the server side, and the service would consume the request and do the needful backend processing, and would not have anything to return to the client.

You can see from this source, the PUT script is very similar to the POST script, except for a few differences. One trivial change from POST to PUT is that the option CURLOPT_PUT instead of CURLOPT_POST has been used. Also, unlike in the POST case, where we set the post data using CURLOPT_POSTFIELDS option, we have set the CURLOPT_INFILE and CURLOPT_INFILESIZE options to provide the name of the file and the size of the data in the file to be PUT.

HTTP DELETE

HTTP DELETE verb is also a sensitive verb like HTTP PUT. This is because the verb can be used to delete a resource, and deleting an existing resource requires proper access privileges. For demonstration purposes, we will use the same service script that we used for PUT operation and see how CURL API can be used to invoke HTTP DELETE. Here is the source code.

<?php
$url = 'http://localhost/rest/02/put.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_exec($ch);
curl_close($ch);
?>

As you may notice, unlike the POST or PUT requests, there is no dedicated option in CURL for delete. Rather you have to use the CURLOPT_CUSTOMREQUEST option with the value DELETE to use the DELETE verb. Also note that, in this simple example, when the put.php script received the DELETE request, the script would simply ignore the request, and leave the data file content as it is. Alternatively, the service script could have erased the data file.

unlink("put_data_file.txt");

One of the common uses of the HTTP DELETE operation is to end the life of a resource, as we discussed in the last chapter. As an example, you could delete a database entry mapped to a resource after receiving a DELETE request. We will see this later in this book, in Chapter 4 where we will discuss a real world sample application.

Building the Request with XML Tools

Primary use of web services will be with XML message format. Of course other messaging formats could be used, however, for the purpose of interoperability XML is the preferred format. Before sending a request from a client to a service, we have to build the request message in XML and hand it over to the HTTP transport. While sending the response to the client, the service too needs to build the response in XML. So the same techniques used for building the request on client side could be used to build the response on the service side.

PHP comes with a number of XML parsers, some built-in and some third-party. For almost all common use cases the built-in parser APIs that come with PHP are sufficient.

The two main XML APIs in PHP are the SimpleXML extension (http://www.php.net/manual/en/book.simplexml.php) and the DOM extension (http://www.php.net/manual/en/book.dom.php). Both these XML APIs come with PHP 5 and they are built-in by default, meaning there are no additional installation steps to enable them. Both of them are based on libxml XML parser (http://www.xmlsoft.org/). Since they are based on libxml, which is a parser written in C, these PHP parser APIs yield high performance while processing XML.

While using XML parsers there are two main modes of operation. One is to build the XML structure that we want, either to write that to a file or to send that over the network. The other mode of operation is to parse XML that is read from a file or from a received stream over a network interface. Reading an XML stream from a file or a network interface and building an equivalent XML object structure in PHP (or any other programming language) is termed as de-serialization. Writing an XML stream to a file or a network interface from an XML object structure is termed as serialization.

Coming back to the topic of building the request, we must build the XML object tree using some PHP code and serialize that object tree to get the string representation of the XML object tree.

SimpleXML

The most simple way to build an XML payload with SimpleXML is to use the XML string and pass it to the SimpleXMLElement constructor. However, for most of the dynamic applications we should be able to form the request payload on the fly. Hence we cannot always assume the luxury of pre-defined knowledge on what the content of the XML payload would be. However, it is reasonable to assume that all applications would have some knowledge of the overall structure of the XML payload to be sent in the request.

<?php
$xmlstr = <<<XML
<books>
<book>
<title/>
</book>
</books>
XML;
$xml = new SimpleXMLElement($xmlstr);
$book = $xml->book[0];
$book->addAttribute('type', 'Computer'),
$book->title = 'RESTful Web Services!';
$author = $xml->book[0]->addChild('author'),
$author->addChild('name', 'Sami'),
echo $xml->asXML();
?>

In the above example, first an XML template is defined with the variable $xmlstr. The variable is initialized to contain a valid XML string, however it does not have any useful content to start with. So we are first defining a structure for the XML message using a simple string and then we add the content programmatically. The output from the previous script is'Sami'.

Next, a SimpleXMLElement instance is created with the XML string that was defined. With the above source code, the XML structure that we want to build is as follows:

<books>
<book type="Computer">
<title>PHP Web Services</title>
<author><name>Sami</name></author>
</book>
</books>

So starting from the initial template XML structure, the first thing we have to do is to add the type attribute to the book element with the value Computer. Basically, with this attribute we want to express that the type of book is Computer. To do this, first we access the first book element in the XML template. This is done with this line:

$book = $xml->book[0];

The array notation with the index 0 means that we want the first element. In fact, there is only one book element in the template. However, we still have to use the indexing mechanism because in an XML document it is quite possible to have more than one element with the same name and the PHP API uses the indexing mechanism to cater for that situation. The addAttribute method is used to add the attribute to the desired element.

$book->addAttribute('type', 'Computer'),

The second important operation done in this source code is setting the title text to PHP Web Services. This can be done by setting the title element of the PHP array structure element with the name book to the desired text. The title array element is accessed using $book->title operation.

$book->title = 'RESTful Web Services!';

The next section of the code adds two elements. author is the parent element and name is the child element, and the child consists of text "Sami". The author element is added to the book element and the name is added to the author element. The addChild() method is used to get the job done.

$author = $xml->book[0]->addChild('author'),
$author->addChild('name', 'Sami'),

The final step in the code that is the call to the operation as XML() serializes the XML object tree that we build.

DOM

DOM API is another XML API available in PHP that is built-in. The following source code will build the same XML tree that we saw in the previous section using the DOM API.

<?php
$xmlstr = <<<XML
<books>
<book>
<title/>
</book>
</books>
XML;
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadXML($xmlstr);
$books = $doc->getElementsByTagName('book'),
$books->item(0)->setAttribute('type', 'Computer'),
$books->item(0)->childNodes->item(0)->nodeValue = 'RESTful Web Services';
$author_node = $doc->createElement('author'),
$books->item(0)->appendChild($author_node);
$name_node = $doc->createElement('name'),
$name_node->nodeValue = 'Sami';
$author_node->appendChild($name_node);
echo $doc->saveXML();
?>

Comparatively this source code is a bit lengthier compared to the SimpleXML based source code doing the identical job. However, it must be noted that the DOM API is much more comprehensive and feature-rich compared to the SimpleXML API. You can get a feel of this if you compare the API documentation of the two APIs. (The links to the API documents were given earlier in this chapter.)

Processing the Response

Once the response is received, the client needs to de-serialize the response XML message received from the service. The service too needs to de-serialize the incoming request received from the client. In the previous section we saw how to build the XML tree. In this section we will explore how to parse an XML document and then traverse that parsed XML tree.

SimpleXML

Let's look at how to use the SimpleXML API to parse an XML document. In this section, we will use a file named book.xml with the following content.

<?xml version="1.0"?>
<books>
<book type="Computer">
<title>PHP Web Services</title>
<author><name>Sami</name></author>
</book> </books>

Note that this XML is the same as the XML structure that we had built in the previous section. The only difference is that we are going to read and traverse the XML tree rather than trying to build the XML tree.

<?php
$xml = simplexml_load_file('book.xml'),
$book = $xml->book[0];
echo "Book title : " . $book->title ."
";
echo "Book author name : " . $book->author->name ."
";
$attributes = $book->attributes();
echo "Book type : " . $attributes['type'] ."
";
?>

In this code, we first load the book.xml file from the file system.

$xml = simplexml_load_file('book.xml'),

Then we access the first element in the XML file with the name book.

$book = $xml->book[0];

And then we access the book information and display those.

echo "Book title : " . $book->title ."
";
echo "Book author name : " . $book->author->name ."
";
$attributes = $book->attributes();
echo "Book type : " . $attributes['type'] ."
";

DOM

Let's see how we can parse the same XML file and traverse the XML tree using the DOM API.

<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->load('book.xml');
$books = $doc->getElementsByTagName('book');
echo "Book title : " . $books->item(0)->childNodes->item(0)->nodeValue ."
";
echo "Book author name : " . $books->item(0)->childNodes->item(1)->nodeValue ."
";
echo "Book type : " . $books->item(0)->getAttribute('type')."
";
?>

In this code, we first create a DOMDocument instance and set the preserveWhiteSpace option to false. What this means is that the parser should remove the redundant white spaces present between the elements while parsing the XML document. The next step in the source code is to load the book.xml file form the file system.

$doc->load('book.xml');

Then we access the set of elements in the XML file with the name book.

$books = $doc->getElementsByTagName('book'),

Of course there is only one book element in the document, but as explained earlier, the parser provides an array notation in the API to accommodate the possibility of the presence of multiple elements with the same name.

Next we access the title and author name elements.

echo "Book title : " . $books->item(0)->childNodes->item(0)->nodeValue ."
";
echo "Book author name : " . $books->item(0)->childNodes->item(1)->nodeValue ."
";

Finally the getAttribute() method is used to access the type attribute.

echo "Book type : " . $books->item(0)->getAttribute('type')."
";

If you run the SimpleXML based PHP script and the DOM API based PHP script given in the above section, you will get identical output on the console.

Consuming Flickr

In this section, we will use the HTTP client libraries and an XML parser API to consume the Flickr REST API. Flickr is a popular web-based application that allows you to share your photos on the Internet. The Flickr API consists of a set of callable methods and some API endpoints that allows developers to use the Flickr services by integrating Flickr to their applications. To perform an action using the Flickr API, you need to select the relevant operation from the API, send a request to its endpoint specifying a method and some arguments and then you will receive a formatted response.

Note that you have to get a Flickr API key for yourself to run the samples given in this section. Details on how to get a Flickr API key can be found at http://www.flickr.com/services/api/misc.api_keys.html.

First let's use a simple API call to get familiar with the concepts related to the Flickr API. In this first sample we will search for a Flickr user by name.

The complete Flickr API can be found on the URL http://www.flickr.com/services/api/. Out of this, we will use the method call findByUsername. The documentation for this method could be found at http://www.flickr.com/services/api/flickr.people.findByUsername.html.

<?php
$base_url = 'http://api.flickr.com/services/rest/';
$query_string = '';
$params = array (
'method' => 'flickr.people.findByUsername',
'api_key' => 'YOUR_API_KEY',
'username' => 'Sami'
);
$query_string = http_build_query($params);
$url = $base_url . '?' . $query_string;
$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);
$xml = simplexml_load_string($response);
foreach ($xml->user as $user) {
$attributes = $user->attributes();
echo 'User ID : ' . $attributes['id'] . "
";
echo 'User NSID : ' . $attributes['nsid'] . "
";
}
?>

The $base_url variable is assigned to the base REST URL where Flickr expects all REST requests would be sent to. Each and every operation has an array of request parameters. Details on the request parameters required by a Flickr method call can be found on the respective API documentation page.

All Flickr method calls expect two mandatory parameters in the request:

  • The method name

  • The API key

The first two elements of the $params array represent those two parameters. The third parameter is specific to the operation that we are going to invoke, namely findByUsername.

$params = array (
'method' => 'flickr.people.findByUsername',
'api_key' => 'YOUR_API_KEY',
'username' => 'Sami'
);

Note that, in order to run this PHP script you have to get a Flickr API key for yourself, and replace "YOUR_API_KEY" string with your own API key. Details on how to get a Flickr API key can be found at http://www.flickr.com/services/api/misc.api_keys.html.

In this example, we are going to search for a user named Sami. Hence we set the username parameter in the $params array to that value.

After defining the parameter array, the next step is to append the parameter key value pairs to the request URL. In other words, we have to build a request query string using the parameter array. This is done using a http_build_query function.

Once the query parameter string is formed with the parameters, it is joined with the base URL to form the final URL string. It is this URL string where base URL plus the query parameters are passed to CURL. For this example the final URL will look something like:

http://api.flickr.com/services/rest/?method=flickr.people.findByUsername&api_key=your_api_key&username=Sami&

With the above URL, we access the service using PHP CURL API and the received response is captured to the $response variable. Then that response is passed to the XML parser. SimpleXML API is used in this sample to parse the response. From the API document it is known that the response would be of the following format.

<rsp stat="ok"> <user id="12037949632@N01" nsid="12037949632@N01">
<username>Stewart</username>
</user> </rsp>

In sync with the expected format of the response this example script prints out the user ID and NSID received in the response as shown below:

User ID : 48600079231@N01 User NSID : 48600079231@N01

Photo Search

Now that we are familiar with the Flickr REST API, let's see how to use image search API to find images with a search term.

<?php
$base_url = 'http://api.flickr.com/services/rest/';
$query_string = '';
$params = array (
'method' => 'flickr.photos.search',
'api_key' => 'YOUR_API_KEY',
'tags' => 'flowers',
'per_page' => 10
);
$query_string = http_build_query($params);
$url = $base_url . '?' . $query_string;
$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);
$xml = simplexml_load_string($response);
foreach ($xml->photos->photo as $photo) {
$attributes = $photo->attributes();
$image_url = 'http://farm' . $attributes['farm'] . '.static.flickr.com/' . $attributes['server'] . '/' . $attributes['id'] . '_' . $attributes['secret'] . '.jpg';
echo "<img src='" . $image_url . "'/>";
}
?>

The output from the script is shown below:

Photo Search

This example is quite similar to the previous user search sample. We set the query parameters like in case of the user search: first two are the method name and the API key respectively. Then we set the parameters that are specific to the photo search. We are going to search for the term 'flowers' in photo tags. The per_page parameter is set to 10, meaning we are expecting 10 search results per page.

The XML response from Flickr would be as shown below:

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="222761" perpage="10" total="2227604">
<photo id="2426964909" owner="15366215@N00" secret="53a301dc73" server="3019" farm="4" title="rocio 2 20Apr08 Stansted Airport" ispublic="1" isfriend="0
" isfamily="0" />
<photo id="2427778480" owner="92329419@N00" secret="8edeff5d1c" server="3110" farm="4" title="P1020588" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2426968511" owner="92329419@N00" secret="23ecee7e0d" server="2201" farm="3" title="P1020595" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2427782016" owner="92329419@N00" secret="53d1c19c19" server="2136" farm="3" title="P1020592" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2426971113" owner="92329419@N00" secret="55ff6a4ab5" server="3263" farm="4" title="P1020599" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2426962095" owner="23913224@N08" secret="d7f09ccf14" server="2417" farm="3" title="Petunia Flowers" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2427775060" owner="23913224@N08" secret="ff84f68c5e" server="3002" farm="4" title="IMG_6668" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2426970287" owner="92329419@N00" secret="df75b2cb3d" server="3202" farm="4" title="P1020596" ispublic="1" isfriend="0" isfamily="0" />
<photo id="2426961859" owner="23913224@N08" secret="68391f48dc" server="3136" farm="4" title="Petunia in Bahrain" ispublic="1" isfriend="0" isfamily="0"
/>
<photo id="2427778762" owner="15366215@N00" secret="d9b82cfa07" server="2205" farm="3" title="rocio 1 20Apr08,Stansted airport" ispublic="1" isfriend="0
" isfamily="0" />
</photos>
</rsp>

There are other optional parameters that could be used while doing photo search. Details of the complete photo search API could be found at http://www.flickr.com/services/api/flickr.photos.search.html.

Once we have built the query parameters and sent the request to Flickr using CURL API and got the response, we pass that response to the XML parser.

For each photo element in the response, we build the image URL in the sample PHP script. Information on how to extract the real image URL from the response returned is documented at http://www.flickr.com/services/api/misc.urls.html.

The output from this PHP script would look as follows::

You can view this with a browser and see the photos corresponding to the search displayed.

Here is a sample output from this script:

Photo Search

Photo Search with Information

Let's extend the photo search example to include more image information. In this example, we will first do a photo search like we did in the previous PHP script and, for each result, get more information such as image tags and web page URL for the image.

<?php
$base_url = 'http://api.flickr.com/services/rest/';
$query_string = '';
$params = array (
'method' => 'flickr.photos.search',
'api_key' => 'YOUR_API_KEY',
'tags' => 'flowers',
'per_page' => 10
);
$query_string = http_build_query($params);
$url = "$base_url?$query_string";
$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);
$xml = simplexml_load_string($response);
foreach ($xml->photos->photo as $photo) {
$attributes = $photo->attributes();
$image_url = 'http://farm' . $attributes['farm'] . '.static.flickr.com/' . $attributes['server'] . '/' . $attributes['id'] . '_' . $attributes['secret'] . '.jpg';
echo '<img src='' . $image_url . ''/>'."
";
$params = array (
'method' => 'flickr.photos.getInfo',
'api_key' => 'YOUR_API_KEY',
'photo_id' => $attributes['id']
);
$query_string = '';
foreach ($params as $key => $value) {
$query_string .= "$key=" . urlencode($value) . "&";
}
Flickr REST APIimage information, searching$url = "$base_url?$query_string";
$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);
$xml = simplexml_load_string($response);
echo '<a href='' . $xml->photo->urls[0]->url . ''>'. $xml->photo->title . '</a>' ."
";
echo "<ul>
";
foreach ($xml->photo->tags->tag as $tag)
echo '<li>'. $tag . '</li>'."
";
echo "</ul>
";
}
?>

In this sample, we first get 10 search results for the term flowers, and then for each photo in the search result getInfo operation is invoked in the Flickr REST API.

The getInfo operation would return a response that looks like the following response:

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photo id="2426991275" secret="0880bd8ed7" server="2225" farm="3" dateuploaded="1208690404" isfavorite="0" license="0" rotation="0" originalsecret="eb3e38e1ee" originalformat="jpg" media="photo">
<owner nsid="22966172@N03" username="joergschickedanz" realname="Joerg Schickedanz" location="Leipzig, Germany" />
<title>Im Garten April 2008</title>
<description />
<visibility ispublic="1" isfriend="0" isfamily="0" />
<dates posted="1208690404" taken="2008-04-21 10:30:39" takengranularity="0" lastupdate="1208690407" />
<editability cancomment="0" canaddmeta="0" />
<usage candownload="1" canblog="0" canprint="0" />
<comments>0</comments>
<notes />
<tags>
<tag id="22943118-2426991275-2620" author="22966172@N03" raw="spring" machine_tag="0">spring</tag>
<tag id="22943118-2426991275-236" author="22966172@N03" raw="roses" machine_tag="0">roses</tag>
<tag id="22943118-2426991275-140" author="22966172@N03" raw="flowers" machine_tag="0">flowers</tag>
</tags>
<urls>
<url type="photopage">http://www.flickr.com/photos/22966172@N03/2426991275/</url>
</urls>
</photo>
</rsp>

In our example PHP script, we extract the URL, title and the tags from this information. Note that the URL is not the URL of the image; rather it is the URL of the page in which Flickr displays the image.

The output of this script would be:

<img src='http://farm3.static.flickr.com/2374/2427821192_72c38a272e.jpg'/>
<a href='http://www.flickr.com/photos/chrisilstrup/2427821192/'>Crocus</a>
<ul>
<li>spring</li>
<li>flowers</li>
</ul>
<img src='http://farm3.static.flickr.com/2045/2427822144_f8157e450a.jpg'/>
<a href='http://www.flickr.com/photos/mmakri/2427822144/'>Flower Drops</a>
<ul>
<li>flower</li>
<li>drop</li>
<li>drops</li>
<li>water</li>
<li>flowers</li>
</ul>

Here is a sample screen shot from this script:

Photo Search with Information

The PHP script does the job, but it is not the cleanest of the source code. There is considerable code duplication. It could be improved to make it more modular and also make the code more reusable for future REST applications that you would implement. Here is the same script, but with less code duplication and more modularity.

<?php
function build_query_string(array $params) {
$query_string = http_build_query($params);
return $query_string;
}
function curl_get($url) {
$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($client);
curl_close($client);
return $response;
}
$base_url = 'http://api.flickr.com/services/rest/';
$api_key = 'YOUR_API_KEY';
$params = array (
'method' => 'flickr.photos.search',
'api_key' => $api_key,
'tags' => 'flowers',
'per_page' => 10
);
$url = "$base_url?" . build_query_string($params);
$response = curl_get($url);
$xml = simplexml_load_string($response);
foreach ($xml->photos->photo as $photo) {
$attributes = $photo->attributes();
$image_url = 'http://farm' . $attributes['farm'] . '.static.flickr.com/' . $attributes['server'] . '/' . $attributes['id'] . '_' . $attributes['secret'] . '.jpg';
echo '<img src='' . $image_url . ''/>' . "
";
$params = array (
'method' => 'flickr.photos.getInfo',
'api_key' => $api_key,
'photo_id' => $attributes['id']
);
Flickr REST APIimage information, searching$url = "$base_url?" . build_query_string($params);
$response = curl_get($url);
$xml = simplexml_load_string($response);
echo '<a href='' . $xml->photo->urls[0]->url . ''>' . $xml->photo->title . '</a>' . "
";
echo "<ul>
";
foreach ($xml->photo->tags->tag as $tag)
echo '<li>' . $tag . '</li>' . "
";
echo "</ul>
";
}
?>

The output from the script is as follows:

Photo Search with Information

In this section, it was demonstrated how to use CURL HTTP client library and SimpleXML parser API to consume Flickr REST API. If you are interested in a complete PHP library that can be used to make use of more operations,http://sourceforge.net/projects/phlickr/ would be a good choice.

Summary

While providing and consuming REST style web services, the primary pre-requisites are an HTTP server or an HTTP client library and an XML parser library. In this chapter, we saw how to use the PHP CURL API to consume web services using various HTTP verbs such as HTTP GET, POST, PUT and DELETE. The DOM API and SimpleXML API for building XML object structures and parsing XML streams were also discussed.

We discussed in detail how to build XML request payloads and also how to parse XML response payloads.

The final section of this chapter demonstrated how to use the HTTP client features and XML parser features to invoke the Flickr REST API.

phpFlickr (http://sourceforge.net/projects/phpflickr) provides a PHP class that wraps the Flickr API. It has easy to use functions and also contains functions that aggregate data from multiple Flickr API methods. PEAR::Flickr_API (http://code.iamcal.com/php/flickr/readme.htm) is another PHP package that provides an easy to use PHP class to deal with the Flickr API. Apart from using them to consume Flickr services, you can also use them to understand REST programming principles by having a look into the source code of these packages.

In the next chapter,we will look into some example use cases where REST is used in the real world.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.192.79