Home » 2008 » August » 01 » Custom Request Methods And PHP

Custom Request Methods And PHP

By default, PHP (along with web browsers and HTML in general) uses two of the eight defined HTTP request methods. The eight methods are: HEAD, GET, POST, PUT, DELETE, TRACE, OPTIONS, and CONNECT. GET is the most widely used, followed by POST. Whenever you type a URL into your browser’s address bar, select a bookmark, or click a link you’re doing a GET. When you submit a form on a web page the method will be either GET or POST.

RESTfully designed web-services use POST, GET, PUT, and DELETE.

Behind the scenes a basic GET request looks like this:

GET /path/to/file.php HTTP/1.1
Host: www.domain.com

If you were to type this URL into your browser it would look like http://www.domain.com/path/to/file.php

Similarly, a POST to the same URL would look like this:

POST /path/to/file.php HTTP/1.1
Host: www.domain.com

(Note: For the purpose of these examples I’m leaving out other request headers such as User-Agent, Keep-Alive, Connection, etc. that you might normally see when using a web browser)

When you do a GET or POST you can also pass in variables. Consider a web page with a form that asks you to submit your first and last name.

The GET request might look like this:

GET /path/to/file.php?FirstName=John&LastName=Doe HTTP/1.1
Host: www.domain.com

As you can see, the variables are attached to the URL. In your browser this would look like http://www.domain.com/path/to/file.php?FirstName=John&LastName=Doe. These type of request variables are sometimes known as GET variables.

The POST version of this request would look like this:

POST /path/to/file.php HTTP/1.1
Host: www.domain.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

FirstName=John&LastName=Doe

As you can see, the variables aren’t appended to the URL in a POST, but instead submitted following the request headers. Variables submitted in this way are sometimes known as POST variables. In this example I also set the Content-Length and Content-Type headers indicating that this POST was submitting name/value pairs. You can also submit other data via POST such as uploading a file (and you would want to set the Content-Type appropriately).

PHP has two superglobals called $_GET and $_POST. These arrays are automatically populated by PHP based on the request.

It should be noted that it’s technically possible to submit a POST request with both GET and POST-type variables.

POST /path/to/file.php?variable1=value1&variable2=value2 HTTP/1.1
Host: www.domain.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

FirstName=John&LastName=Doe

In this case, $_GET would be populated with:

Array
(
    [variable1] => value1
    [variable2] => value2
)

And $_POST would be populated with:

Array
(
    [FirstName] => John
    [LastName] => Doe
)

Using A Custom Request Method
What happens if you want to create a RESTful web-service and submit a PUT request to a PHP page? What if you want to make up your own request method; how do you handle that with PHP?

Consider the following request:

MYMETHOD /path/to/file.php HTTP/1.1
Host: www.domain.com
Content-Length: 27

FirstName=John&LastName=Doe

In this example I’m submitting POST-style variables with my own made-up request method called MYMETHOD. I could just as easily substitute MYMETHOD with PUT. You can easily submit this type of request with a Firefox extension called RestTest. You can verify what is actually being sent with another extension called Live HTTP Headers.

(Note: Some servers may be locked down to only allow certain request methods. If you make a request with a method that’s not allowed then the server will respond back with a 405 Method Not Allowed error. A 405 response will include a response header letting you know which methods are allowed.)

If you don’t want to rely on the convenience of $_GET and $_POST then you can always parse out the raw data yourself.

  • $_SERVER['QUERY_STRING'] is the raw version of $_GET
  • php://input is the raw version of $_POST

You should never have to parse out the query string manually, but $_POST is only populated if the request method is POST and an appropriate Content-Type is set.

To get our raw MYMETHOD data we could do something like this:

if ($_SERVER['REQUEST_METHOD'] == 'MYMETHOD')
{
  $raw_data = file_get_contents('php://input');
}

We could then parse out the raw data into a $_MYMETHOD variable (to mimic $_GET and $_POST).

$array = explode('&', $raw_data);
foreach($array as $item)
{
  list($key, $value) = explode('=', $item);
  $_MYMETHOD[$key] = $value;
}

Putting It All Together
Besides using a tool like RestTest, we can also create a web page that submits a MYMETHOD request. We’ll do this by using some JavaScript and making an Ajax request with the XMLHttpRequest object.

<?php
if ($_SERVER['REQUEST_METHOD'] == 'MYMETHOD' && strpos($_SERVER['CONTENT_TYPE'], 'application/x-javascript') !== FALSE):
  $raw_data = file_get_contents('php://input');
  $array = explode('&', $raw_data);
  foreach($array as $item)
  {
    list($key, $value) = explode('=', $item);
    $_MYMETHOD[$key] = $value;
  }
  print_r($_MYMETHOD);

else:
?>
<html>
<head>
<script type="text/javascript">
/**
 * Bridge XMLHTTP to XMLHttpRequest in pre-7.0 Internet Explorers
 */
if( typeof XMLHttpRequest == "undefined" )
  XMLHttpRequest = function() {
    try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP") }     catch(e) {}
    try { return new ActiveXObject("Microsoft.XMLHTTP") }  catch(e) {}
    throw new Error( "This browser does not support XMLHttpRequest or XMLHTTP." )
  };

function ajax(url, vars) {
  var request = new XMLHttpRequest();
  request.open("MYMETHOD", url, true);
  request.setRequestHeader("Content-Type", "application/x-javascript;");

  request.onreadystatechange = function() {
    if (request.readyState == 4 && request.status == 200) {
      if (request.responseText) {
        alert(request.responseText);
      }
    }
  };

  request.send(vars);
}
</script>
</head>
<body>

<input type="button" value="click for ajax" onclick="javascript:ajax('<?php echo $_SERVER['PHP_SELF']; ?>', 'FirstName=John&amp;LastName=Doe');" />

</body>
</html>
<?php endif; ?>

If you copy this into a PHP file (i.e. mymethod.php), upload it to a PHP-enabled web server, and navigate to it with your web browser you’ll see a button that says click for ajax. If you click the button, an asynchronous MYMETHOD request will be sent, the server will parse out the sent name/value pairs and send the processed data back to the browser. The user will then be presented with an alert popup containing the following text:

Array
(
    [FirstName] => John
    [LastName] => Doe
)

About this entry