Building a RESTful Web application with PHP

Recently I’ve been putting together a Web application for a research project. I decided it was about time I really looked properly into REST so my Web interfaces are better structured. I won’t go into all the benefits here, you can read for yourself. Suffice to say it seems like a good approach to take.

This is quite a long article and you might only be interested in some of it so here are the sections:

If you have an suggestions for improvement, please let me know – this was a first attempt!

Some credit for this article should go to lornajane for her PHP REST Server articles (Part 1, Part 2, Part 3) which I used as a good starting point.

Getting access to request data

Getting access to HTTP GET arguments or POST data is well known and easy. With a REST interface you are likely to support other HTTP verbs such as PUT and DELETE. Getting data from these requests is not obvious but luckily lornajane had worked this out for me:

parse_str(file_get_contents('php://input'), $arguments);

Returning appropriate responses

With REST you should really make use of the HTTP Status Codes for all requests (rather that using 200 OK for everything). In PHP, this can be done with the header function in a couple of ways:

// When setting just the status code
header('HTTP/1.1 405 Method Not Allowed');
// When you're setting another header at the same time
header('Allow: GET, HEAD, POST, DELETE', true, 405);

I haven’t found a way of sending just the status code number (e.g. 405) without specifying the exact text (‘Method Not Allowed’) but these are part of a fixed specification so it’s not a huge problem.

The following is a list of status codes that I’ve used and why:

Handling different data formats

As URLs are supposed to represent resources in REST, it is a feasible requirement that client applications would like to receive responses from the same URL in different formats. Clients can specify the data formats they are capable of understanding using the HTTP Accept header. In Javacript this can be set using the setRequestHeader method on the XMLHttpRequest object. Using jQuery as my current Javascript library of choice, the code for doing this is as follows:

$.ajax({
  type: method, // GET, POST, PUT, DELETE etc.
  url: url, // The actual URL to make the request
  data: data, // Any data/parameters to send to the server
  beforeSend: function(xmlHttpRequest) {
    xmlHttpRequest.setRequestHeader('Accept', format); // MIME Type
  }
});

This then needs to be handled by the server. In PHP this data can be retrieved using $_SERVER['HTTP_ACCEPT']. I also found a handy library for parsing this header according to the specification (not trivial), cleverly named ‘HTTP_ACCEPT‘. I then wanted a way of knowing the most appropriate format from a list of formats I would support so I threw the following code together:

$accept = new HTTP_Accept($_SERVER['HTTP_ACCEPT']);
foreach ($supportedFormats as $supportedFormat) {
  $supportedFormatQuality = $accept->getQuality($supportedFormat);
  if ((!isset($bestFormat) && $supportedFormatQuality > 0) ||
       $bestQuality < $supportedFormatQuality) {
    $bestFormat = $supportedFormat;
    $bestQuality = $supportedFormatQuality;
  }
}

The server also needs to specify the type of content it is returning; this can be done using the Content-Type header as follows:

header("Content-Type: $format");

Passing all requests to a single PHP script

I needed all requests with a certain URL prefix to be handled by a single script. This was easily solved using the following URL re-writing rule in a .htaccess file:

Options +FollowSymLinks
RewriteEngine on
RewriteRule ^.*$ index.php

Note that I had to enable the mod_rewrite module in Apache and ensure that directives could be overridden with the following:

<Directory /var/www/>
  AllowOverride All
</Directory>

Determining the full requested URL

Another requirement of my application complicated by URL rewriting was that I needed access to the full URL. I achieved this with the following bit of code:

$protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
$location = $_SERVER['REQUEST_URI'];
if ($_SERVER['QUERY_STRING']) {
  $location = substr($location, 0, strrpos($location, $_SERVER['QUERY_STRING']) - 1);
}
$url = $protocol.'://'.$_SERVER['HTTP_HOST'].$location;

A generic REST Service class

To allow me to reuse some of the REST code I’d created, I put it into a generic REST Service class which I subclassed and replaced different methods for different means:

class RestService {

  private $supportedMethods;

  public function __construct($supportedMethods) {
    $this->supportedMethods = $supportedMethods;
  }

  public function handleRawRequest($_SERVER, $_GET, $_POST) {
    $url = $this->getFullUrl($_SERVER);
    $method = $_SERVER['REQUEST_METHOD'];
    switch ($method) {
      case 'GET':
      case 'HEAD':
        $arguments = $_GET;
        break;
      case 'POST':
        $arguments = $_POST;
        break;
      case 'PUT':
      case 'DELETE':
        parse_str(file_get_contents('php://input'), $arguments);
        break;
    }
    $accept = $_SERVER['HTTP_ACCEPT'];
    $this->handleRequest($url, $method, $arguments, $accept);
  }

  protected function getFullUrl($_SERVER) {
    $protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
    $location = $_SERVER['REQUEST_URI'];
    if ($_SERVER['QUERY_STRING']) {
      $location = substr($location, 0, strrpos($location, $_SERVER['QUERY_STRING']) - 1);
    }
    return $protocol.'://'.$_SERVER['HTTP_HOST'].$location;
  }

  public function handleRequest($url, $method, $arguments, $accept) {
    switch($method) {
      case 'GET':
        $this->performGet($url, $arguments, $accept);
        break;
      case 'HEAD':
        $this->performHead($url, $arguments, $accept);
        break;
      case 'POST':
        $this->performPost($url, $arguments, $accept);
        break;
      case 'PUT':
        $this->performPut($url, $arguments, $accept);
        break;
      case 'DELETE':
        $this->performDelete($url, $arguments, $accept);
        break;
      default:
        /* 501 (Not Implemented) for any unknown methods */
        header('Allow: ' . $this->supportedMethods, true, 501);
    }
  }

  protected function methodNotAllowedResponse() {
    /* 405 (Method Not Allowed) */
    header('Allow: ' . $this->supportedMethods, true, 405);
  }

  public function performGet($url, $arguments, $accept) {
    $this->methodNotAllowedResponse();
  }

  public function performHead($url, $arguments, $accept) {
    $this->methodNotAllowedResponse();
  }

  public function performPost($url, $arguments, $accept) {
    $this->methodNotAllowedResponse();
  }

  public function performPut($url, $arguments, $accept) {
    $this->methodNotAllowedResponse();
  }

  public function performDelete($url, $arguments, $accept) {
    $this->methodNotAllowedResponse();
  }

}

30 thoughts on “Building a RESTful Web application with PHP

  1. nice article! really the first well web resource on PHP-REST web service i found! It's simple and clear!REST is simple in its concepts, but i think there is still much confusion around what's the differences between the diffrent kind of web-services. I find this article a good starting point for those who doesnt know (or believe to know) about web-services.

  2. nice, REST finally started to make sense to me a few days ago when I was messing with headers. This article filled in a lot of the gaps. Thanks.

  3. This is excellent. Does anyone have any sample code showing the contents of index.php as well as an example of a class that implements RestService?

  4. Thanks for the great write-up. I'm planning on giving your directions a spin in a few days. Wasn't easy to find an article as good as yours to get me started, so thanks a million.-Ace

  5. Pingback: RESTful in PHP: first piece of code « Lietoservetruth's Blog

  6. “Here air jordan 21 products xx, has fashion model, superior quality and service, cheap price and updates quickly.I support strongly always! I want to buy XX, I hesitate to select which style more better.Hope your unique recommends.

  7. Absolutely excellent article!  Thank you!

    I have read at least a dozen others tonight, but this was the first one that made complete sense.

    For those who feel that REST isn’t useful, try building an application with regular get/post and an action parameter.  You’ll see how useful REST is within the first few weeks of development.

  8. Excellent article!

    one note, this line of code didn’t work for me
    $protocol = $_SERVER['HTTPS'] == ‘on’ ? ‘https’ : ‘http';I rewrote it and now it works:
       
    if (!empty($_SERVER['HTTPS'])) {
            $protocol = ‘https';
        } else {
            $protocol = ‘http';
        }

    Also, your reply to PepperHill:

    $service->handleRequest($_SERVER, $_GET, $_POST);

    Shouldn’t it be
    $service->handleRawRequest($_SERVER, $_GET, $_POST);

    Thanks again

    • Hey, thanks for your comments. No idea if the HTTPS thing is a change in PHP or a platform-specific thing or what but glad you found a solution. Yes, you’re right about my reply to PepperHill – good spot!

  9. Great article!

    One question: How would you handle CSS/JS/IMG files? The rewrite cond converts requests for css/js/etc files to index.php. How do you add exceptions?

  10. A very useful post for a beginner like me. I actually required REST to access date from mysql db for my android app, I already have a web app doing it on the browser. Can I have both of these for my app that has a web front end and mobile application front end ? Like REST for mobile and normal PHP for web side interactions ? Thanks again for the nice post on REST.

    • You can certainly have a single HTTP API that both your web and mobile front ends can interact with to access data in your MySQL database. That API can be RESTful if you design it that way. If you already have an API setup for the web app, then you could just re-use that API for the mobile interface (unless it’s sending HTML mark-up or something which I would generally recommend against).

      Does that answer your question?

      • I didn’t have an idea about involving REST in my design, until I understood the usefulness of REST for android. May be I should prefer to write API instead of just PHP’s that throws out formatted data with HTML tags. Thanks for your input, I have got more clear about the whole thing.

  11. anyway you have a download to a full example of a REST api implementation, I would like to examine an entire set of pages/supporting pages in PHP of a real world fully functional REST api

  12. Dear Gareth,
    I am seeking a RESTful code that fully work & can run . I am totally newbie in that . So not much idea abt it. So expect a complete hello world stuff

    Thanks,
    Anes

  13. For two weeks I make a rest api but not fully understand how to use it and implemention to website or web app but this tutorial makes me understand to start again. Btw thanks for share.

Leave a Reply

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 / Change )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s