You are previewing PHP Web Services.

PHP Web Services

Cover of PHP Web Services by Lorna Jane Mitchell Published by O'Reilly Media, Inc.
  1. Preface
    1. Conventions Used in This Book
    2. Using Code Examples
    3. Safari® Books Online
    4. How to Contact Us
  2. 1. Introduction
  3. 2. HTTP
    1. Examining HTTP
      1. Curl
      2. Browser Tools
      3. PHP
  4. 3. Request and Response
    1. Clients and Servers
  5. 4. HTTP Verbs
    1. GET
    2. POST
    3. Other HTTP Verbs
  6. 5. Headers
    1. Request and Response Headers
    2. Common HTTP Headers
      1. User-Agent
      2. Headers for Content Negotiation
      3. Authorization
      4. Custom Headers
  7. 6. Cookies
    1. Cookie Mechanics
    2. Working With Cookies in PHP
  8. 7. JSON
    1. When to Choose JSON
    2. Handling JSON with PHP
    3. JSON in Existing APIs
  9. 8. XML
    1. When To Choose XML
    2. XML in PHP
    3. XML in Existing APIs
  10. 9. RPC and SOAP Services
    1. RPC
    2. SOAP
      1. WSDL
      2. PHP SOAP Client
      3. PHP SOAP Server
      4. Generating a WSDL File from PHP
      5. PHP Client and Server with WSDL
  11. 10. REST
    1. RESTful URLs
    2. Resource Structure and Hypermedia
    3. Data and Media Types
    4. HTTP Features in REST
      1. Create Resources
      2. Read Records
      3. Update Records
      4. Delete Records
    5. Additional Headers in RESTful Services
      1. Authorisation Headers
      2. Caching Headers
    6. RESTful vs Useful
  12. 11. Debugging Web Services
    1. Debug Output
    2. Logging
    3. Debugging From Outside Your Application
      1. Wireshark
      2. Charles Proxy
    4. Finding the Tool for the Job
  13. 12. Making Service Design Decisions
    1. Service Type Decisions
    2. Consider Data Formats
    3. Customisable Experiences
    4. Pick Your Defaults
  14. 13. Building a Robust Service
    1. Consistency is Key
      1. Consistent and Meaningful Naming
      2. Common Validation Rules
      3. Predictable Structures
    2. Making Design Decisions for Robustness
  15. 14. Error Handling in APIs
    1. Output Format
    2. Meaningful Error Messages
    3. What To Do When You See Errors
  16. 15. Documentation
    1. Overview Documentation
    2. API Documentation
    3. Interactive Documentation
    4. Tutorials and the Wider Ecosystem
  17. A. A Guide To Common Status Codes
  18. B. Common HTTP Headers
  19. About the Author
  20. Copyright
O'Reilly logo

Chapter 4. HTTP Verbs

The HTTP verbs, such as GET and POST let us send our intention along with the URL to instruct the server what exactly we’d like to do with this resource. Web requests are more than just a series of addresses, and the verbs contribute to the rich fabric of the journey.

I mentioned GET and POST because it’s very likely you’re already familiar with those. There are many verbs we can use with HTTP, in fact we can even invent our own! We will move on later in the chapter to look at some of the other verbs we can use and when. For now, let’s revisit GET and POST in some detail, looking at when we use each one and what the differences are.


URLs used with GET can be bookmarked, they can be called as many times as needed, and the request should not effect change. A great example of using a GET request when filling in a web form is when using a search form, which should always use GET. Searches can be repeated safely, and the URLs can be shared.

Consider the simple form in Figure 4-1, which simply allows the user to state which category of results they’d like and how many to show. The page which displays this page and the (placeholder) search results can be as simple as:


if(empty($_GET)) {


<form name="search" method="get">
    <select name="category">
        <option value="entertainment">Entertainment</option>
        <option value="sport">Sport</option>
        <option value="technology">Technology</option>
    </select> <br />

    Rows per page: <select name="rows">
        <option value="10">10</option>
        <option value="20">20</option>
        <option value="50">50</option>
    </select> <br />

    <input type="submit" value="Search" />

} else {
    echo "Wonderfully filtered search results";
An example of a very simple search form
Figure 4-1. An example of a very simple search form

Here you can see that PHP simply checks if it has been given some search criteria (or indeed any data in the $_GET superglobal) and if not, it displays the empty form. If there is data, then it would process it although we’ve kept it very simple for this example. The data gets submitted on the URL when we fill in the form (GET requests typically have no body data), giving a URL like this:


This example shows how PHP can respond to a GET request, but how can it make one? Well, as discussed in Chapter 2, there are many ways we can approach this. For a very quick example, and a simple one when working with GET requests, we can use PHP’s stream handling to make the request for us.


$url = 'http://localhost/book/get-form-page.php';
$data = array("category" => "technology", "rows" => 20);

$get_addr = $url . '?' . http_build_query($data);
$page = file_get_contents($get_addr);
echo $page;

In a real system, it would be prudent to be cautious of the data coming in from external APIs; you would probably want to filter the contents of $page before outputting it or using it anywhere else. As an alternative to using PHP’s stream features, you could use whatever functionality your existing frameworks or libraries offer, or make use of the Curl extension which is built in to PHP. Using Curl, our code would instead look like this:


$url = 'http://localhost/book/get-form-page.php';
$data = array("category" => "technology", "rows" => 20);

$get_addr = $url . '?' . http_build_query($data);
$ch = curl_init($get_addr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$page = curl_exec($ch);
echo $page;

Either of the above approaches will work well when you want to fetch data into your PHP script from an external API or page. Here we’re showing web pages in our examples, but these are the techniques we’ll use whether we’re working with HTML, XML, JSON, or anything else.


In contrast with GET requests, a POST request is one that does cause change on the server which handles the request. These requests shouldn’t be repeated or bookmarked, which is why your browser warns you when it is resubmitting data. We’ll use a POST form when the request changes data on the server side, for example something like Figure 4-2 which shows updating a little bit of user profile information.

Simple form that updates data, sending content via a POST request
Figure 4-2. Simple form that updates data, sending content via a POST request

When we fill in the form with GET, we simply see the variables on the URL. With POST however, the data goes into the body of the request, and we use the Content-Type header to denote what kind of data can be found in the body. When we fill in the form in Figure 4-2, the request looks like this:

POST /book/post-form-page.php HTTP/1.1
Host: localhost
Content-Length: 48
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

In this example, you can see the data in the body, with the Content-Type and Content-Length headers set appropriately so a client could decode the response (more about content negotiation in the headers chapter). PHP knows how to handle form data, so it can parse this out for us and will place the fields into $_POST ready for us to use. Here is the code behind this page, simply showing the form unless there is some incoming data, in which case the data is displayed.


if(empty($_POST)) {


<form name="user" method="post">
    <input type="text" length="60" name="email" /><br />

    Display name:
    <input type="text" length="60" name="display_name" /><br />

    <input type="submit" value="Go" />

} else {
    echo "New user email: " . filter_input(INPUT_POST,
        "email", FILTER_VALIDATE_EMAIL);

It is a very common use case to build PHP forms and parse data in this way, but since we’re looking at how to handle HTTP requests, then we should also consider how we can make the requests as well as respond to them. This is not dissimilar to the way that we made the GET requests. For example to POST data to this form using streams, similar to those in GET, we can use the same basic approach but we should add some context to our stream, telling it which methods, headers and verbs to use.


$url = 'http://localhost/book/post-form-page.php';
$data = array("email" => "", "display_name" => "LornaJane");
$options = array(
    "http" => array(
        "method"  => "POST",
        "header"  => "Content-Type: application/x-www-form-urlencoded",
        "content" => http_build_query($data)

$page = file_get_contents($url, false, stream_context_create($options));
echo $page;

When we POST data to this form, it will output the data we sent rather than the form, so we’ll see “New user email: .com”. This code looks very similar the previous streams example, but here we use stream_context_create() to add some additional information to the stream.

You can see that we add the body content as a simple string, formatted url-wise by http_build_query() and indicate which content type the body is. This means that we can very easily send other data formats when we want to work with data, by formatting the strings correctly and setting the headers.

Here is an example doing exactly the same thing but using the pecl_http extension:


$url = 'http://localhost/book/post-form-page.php';
$data = array("email" => "", "display_name" => "LornaJane");

$request = new HttpRequest($url, HTTP_METH_POST);
$page = $request->getResponseBody();
echo $page;

Since this is a post request, PHP assumes we’re posting a form, but we can set different Content-Type headers if appropriate, and send another format of string data as we’ll see illustrated as we move through the book. When we’re working with non-standard verbs (as we’ll see in the next section) or with data that isn’t from a form post, we can’t access the data by grabbing it from $_POST. Instead, we simply access PHP’s own stream of raw body data with php://input.

Other HTTP Verbs

There are various specifications relating to HTTP and protocols based up on it, and between them they define a wide selection of verbs that can be used with HTTP. Even better, there is always scope for inventing new HTTP verbs; so long as your client and server both know how to handle any verb, then it is valid to use it, however be aware that not everything between these two points will necessarily know how to handle these verbs. Some do not support PATCH for example, or the verbs used by the WebDAV protocol. When working with APIs, particularly RESTful ones, we make use of two additional verbs: PUT and DELETE. We’ll explore REST in detail in a later chapter, for now we will see some simple examples of how to use these less common verbs in our applications.

The simplest of the two is DELETE, because it doesn’t have any body data with it. We can see what kind of request was made to a PHP script acting as a server by inspecting the $_SERVER["REQUEST_METHOD"] value, which will tell us which verb was used in the request.

To make the request from PHP, we simply need to set the verb and then make the request as normal. Here’s an example using the curl extension.


$url = 'http://localhost/book/example-delete.php';

$ch = curl_init($url);

The above simply issues a request to the $url shown, with a DELETE verb.

To use PUT is slightly more involved because, like POST, it can have data accompanying it and the data can be in a variety of formats. Earlier it was mentioned that for incoming form data, PHP will read form encoded values for POST and create a $_POST array for us. There is no equivalent $_PUT superglobal, but we can still make use of the php://input stream to inspect the body data of the request we are responding to.

When PHP is the server responding to PUT requests, we will have code that looks something like this very simple example:


    $data = array();
    $incoming = file_get_contents("php://input");
    parse_str($incoming, $data);
    echo "New user email: " . filter_var($data["email"], FILTER_VALIDATE_EMAIL);
} else {
    echo "um?";

This example inspects the $_SERVER superglobal to see which verb was used, and then responds accordingly. The data coming in to this example will be form-style, so we first use file_get_contents() to grab all the body data, then use parse_str() to decode it. Be careful with parse_str() - if the second argument is omitted, the variables will instead be extracted as local variables rather than contained in an array.

To use PHP to make the request that the above script can handle, we need to create the contents of the body of the request and specify that this is a PUT request. Below is an example built using the pecl_http extension:


$url = 'http://localhost/book/put-form-page.php';
$data = array("email" => "", "display_name" => "LornaJane");

$request = new HttpRequest($url, HTTP_METH_PUT);
$request->setHeaders(array("Content-Type" => "application/x-www-form-urlencoded"));
$page = $request->getResponseBody();
echo $page;

Here we specify a PUT verb, and also set the correct header for the form encoded data. We set the put data, manually building the form elements into a string and then send the request. There’s more about other data formats in a later chapter, but the basic principles of preparing the data and setting the Content-Type header accordingly still stand.

With this knowledge of how to handle GET, POST, DELETE and PUT verbs, we are able to work with many different kinds of API, both as a a client and a server.

The best content for your career. Discover unlimited learning on demand for around $1/day.