The PHP manual has the following to say about the notorious superglobals, $_GET
and $_POST
:
$_GET
An associative array of variables passed to the current script via the HTTP GET method.
Source: php.net
$_POST
An associative array of variables passed to the current script via the HTTP POST method.
Source: php.net
Let’s see how a typical PHP application works, shall we?
When a PHP script is invoked by a web server, it is as the result of a HTTP request. A HTTP request has a target URI and that URI consists of different parts. One of these parts is the query
. That is the part that comes after any question mark. Or more formally:
<scheme>://<authority><path>?<query> absoluteURI = scheme ":" ( hier_part | opaque_part ) hier_part = ( net_path | abs_path ) [ "?" query ] net_path = "//" authority [ abs_path ] abs_path = "/" path_segments
Source: rfc 2396
As the PHP process starts up, the query
gets parsed into an associative array. And for some reason, somebody decided on the unfortunate $_GET
, because it’s what you use for GET requests – right?
Wrong!
All HTTP requests – GET, POST and the lesser known ones – have a URI. Since they all have a URI, they also have a query
, and thus the $_GET
array is available for all of them. In other words, a POST request also has $_GET
parameters. No wonder people get tripped up about HTTP and REST. But it gets worse yet.
In addition to a URI, some HTTP requests may contain a message body; Not all requests (A GET may not, for example) – but some. The most common example of request that contains a message body is the POST type. Enter the $_POST
variable. Like its cousin $_GET
, this is populated at startup, but with the message body parsed as application/x-www-form-urlencoded
. Unlike $_GET
this isn’t part of the HTTP specification, but specifically the kind of encoding that browsers will submit HTML <form>
in. In practise, this is a fairly safe bet, because browsers only are capable of submitting forms as GET and POST, but technically there’s nothing stopping someone from sending a PUT type request with a form-encoded message-body.
Then there is $_FILES
, which is similar to $_POST
, in that it is an interpretation of the message body, but this time according to rfc 1867, which by the way is the recommended encoding for POST requests. Yay!
So now that all the specifications have been summed up, here is my gripe with PHP.
The problem with $_GET
and $_POST
is that a lot of people assume – understandably, but wrongly – that $_GET
is somehow tied to GET requests, and that $_POST
correspondingly is what you use for POST requests. But that’s not the case. A POST request can well have relevant data in $_GET
. Or in $_FILES
. And form-encoding is not restricted to POST requests – Thus $_POST
may contain relevant data for a PUT request.
The current names are confusing and obscures the intention of HTTP; More descriptive names would have been $_QUERY
instead of $_GET
and $_FORM
* instead of $_POST
(Which would match the etymology of the name $_FILES
).
* As has been pointed out in the comments, perhaps $_FORM
isn’t the best of names either.
If it seems like a hassle to change that, allow me to remind that something similar was done a couple of years ago and that didn’t seem to bother anybody back then. But for starters, a clarification of the documentation would be a step in the right direction.
And I won’t even comment on the nastiness of $_REQUEST
.