PHP request and response lifecycle
In abstract the job of every web programming language is to process an incomming HTTP request and produce a HTTP response based on the request data. Every language has its own API to expose the request data to the userland code and to provide a way to produce an response. With this post I want to explain the basic PHP API (which is quickly forgotten under all the abstraction layers which are used today).
POST /tests/test.php?bar=foo HTTP/1.1 Host: 127.0.0.1 User-Agent: Foolib Content-Type: application/x-www-form-urlencoded Connection: Keep-Alive Cookie: baz=foo Content-Length: 7 foo=bar
If such an request arrives to our script we could access the request data with the following variables:
$_GET = [ 'bar' => 'foo', ];
$_GETvariable get filled by the query parameters from the url. PHP uses the parse_str function to convert the query string into an array. Because of that it is not possible to have multiple GET parameters with the same name i.e.
/test.php?bar=foo&bar=barwhich is unusual but possible. Also GET parameter which contain an '.' in the name are replaced by an underscore i.e.
foo_bar. It is possible to create nested arrays by appending "" to the parameter name i.e.
/test.php?bar=foo&bar=bar. This would create an array like
$_POST = [ 'foo' => 'bar', ];
The parsing of the POST body into an array works only if the Content-Type is
application/x-www-form-urlencoded. If this is the case PHP also uses the parse_str function. Because of that all restrictions described for the GET parameters are also applied to the POST parameters.
$_COOKIE = [ 'baz' => 'foo', ];
$_COOKIEvariable contains the key value pairs of the
$_FILES = ;
$_FILESvariable is only filled if the request contains an
$_REQUEST = [ 'bar' => 'foo', 'foo' => 'bar', ];
$_REQUESTvariable contains by default the GET, POST and COOKIE values. On my php.ini I have:
request_order = "GP"which means it contains only GET and POST values.
$_SERVER = [ 'HTTP_HOST' => '127.0.0.1', 'HTTP_USER_AGENT' => 'Foolib', 'HTTP_CONNECTION' => 'Keep-Alive', 'HTTP_COOKIE' => 'baz=foo', 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', 'CONTENT_LENGTH' => '7', 'REMOTE_ADDR' => '127.0.0.1', 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_METHOD' => 'POST', 'QUERY_STRING' => 'bar=foo', 'REQUEST_URI' => '/tests/test.php?bar=foo', ];
$_SERVERvalues contain all headers in the
HTTP_*keys and also meta variables from the webserver. There is an RFC which specifies these meta variables.
$body = file_get_contents('php://input');
In order to access the raw request body we can use the input stream in this case
$bodywould have the value "foo=bar". This is useful for parsing non
application/x-www-form-urlencodedcontent i.e. JSON or XML.
To produce an response we could use the following PHP code:
<?php header('HTTP/1.1 200 OK'); header('Content-Type: text/plain'); setcookie('baz', 'foo'); echo 'foobar';
function writes an raw header to the response. The
Set-Cookie header. With
echo it is
possible to output the response body. There are also some other ways i.e. you
could use the print
function or write to the PHP output stream
Note normally you can only use the header and setcookie function before you output any content. In case output buffering is enabled it is also possible to send an header after sending an output because every response produced by the script gets written into an internal buffer. The buffer is sent either if the script ends or flushed
In the end this would produce the following HTTP response:
HTTP/1.1 200 OK Date: Sat, 27 Dec 2014 21:53:19 GMT X-Powered-By: PHP/5.5.11 Set-Cookie: baz=foo Content-Length: 6 Connection: Keep-Alive Content-Type: text/plain foobar
As conclusion I think the PHP API is not beautiful but its simple and is probably the reason why PHP is so popular.