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
)

Leave a Reply

2 Comments

Archives