Handling HTTP requests in PHP
By Flavio
Tagged: PHP
Learn how to handle HTTP requests in PHP with file-based routing and the superglobals $_GET, $_POST, $_REQUEST, and $_SERVER to read request data.
Let’s see how to handle HTTP requests in PHP.
PHP maps a URL to a file. You create an index.php file and that file answers /.
We saw that with the Hello World example. With MAMP, the page is http://localhost:8888. The built-in server uses http://localhost:8000.
A test.php file answers /test.php on a plain Apache and PHP setup. /test is a different URL. It reaches test.php only with a rewrite rule, or with MultiViews.
The same file runs for GET, POST, and the other verbs. What changes is which superglobal holds the data.
Read the query string
$_GET is a superglobal. PHP creates it for you, and you can read it inside any function without writing global.
It holds the query string. A GET request uses that the most, and a POST can send a query string too.
<?php
$topic = $_GET['topic'] ?? 'php';
echo htmlspecialchars($topic, ENT_QUOTES, 'UTF-8');
Open http://localhost:8888/?topic=forms. The page prints forms. Leave topic off and it prints php.
In PHP 8, reading $_GET['topic'] when the parameter is missing raises Undefined array key "topic". ?? avoids that.
Every value in $_GET is a string. ?count=2 gives you "2", not the number 2. Cast it when you need a number.
htmlspecialchars() matters because you are printing visitor input into HTML.
Read the body
PHP fills $_POST and $_FILES for a POST request whose body is application/x-www-form-urlencoded or multipart/form-data. That is a normal HTML form, or the FormData object in the browser. How to use forms in PHP builds the form. A raw urlencoded body is name=value pairs joined by &.
Check the method before you read $_POST. A GET request leaves it empty.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$topic = $_POST['topic'] ?? '';
echo htmlspecialchars($topic, ENT_QUOTES, 'UTF-8');
}
PUT, PATCH and DELETE also leave $_POST empty. On PHP 8.4 or later, request_parse_body() reads a form body on those verbs and returns the same two arrays:
<?php
[$_POST, $_FILES] = request_parse_body();
request_parse_body() understands those two form content types. The body can be read once. If you already read php://input, the function returns empty data. A JSON body is not a form, and calling request_parse_body() on it throws RequestParseBodyException.
Read JSON from php://input and decode it:
<?php
$data = json_decode(file_get_contents('php://input'), true);
$topic = is_array($data) ? ($data['topic'] ?? '') : '';
json_decode() returns null when the body is not JSON, so the is_array() check keeps $topic a string.
You can send that request with curl:
curl -X POST http://localhost:8888/index.php \
-H 'Content-Type: application/json' \
-d '{"topic":"forms"}'
Before PHP 8.4, read an urlencoded body on PUT or DELETE the same way:
<?php
parse_str(file_get_contents('php://input'), $data);
parse_str() writes the fields into $data. The body topic=forms becomes $data['topic'].
$_REQUEST
$_REQUEST mixes inputs. request_order in php.ini decides which of $_GET, $_POST and $_COOKIE are copied in, and which one wins when the same name appears twice. Later letters overwrite earlier ones. If request_order is empty, PHP uses variables_order, and that default includes cookies.
The php.ini that ships with PHP sets request_order to GP. Cookies stay out, and a POST field overwrites a query parameter with the same name.
My advice is to read $_GET or $_POST, so you know which part of the request sent the value.
$_SERVER
$_SERVER holds this request and the server around it. It is a superglobal too.
You saw phpinfo() before. Drop this into index.php in the MAMP document root:
<?php
phpinfo();
?>
Open localhost:8888 and search $_SERVER. You get the keys and the values for this request:

Take that call out before anyone else can open the site. phpinfo() prints the server configuration, including file paths and loaded modules.
Important ones you might use are
$_SERVER['HTTP_HOST']$_SERVER['HTTP_USER_AGENT']$_SERVER['SERVER_NAME']$_SERVER['SERVER_ADDR']$_SERVER['SERVER_PORT']$_SERVER['DOCUMENT_ROOT']$_SERVER['REQUEST_URI']$_SERVER['SCRIPT_NAME']$_SERVER['REMOTE_ADDR']
This prints the method and the path the visitor asked for:
<?php
echo $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'];
A request to http://localhost:8888/test.php?topic=forms prints GET /test.php?topic=forms.
Those names come from the old CGI interface. If you want to see the same request data from a C program, I wrote How to handle web requests in C with CGI 1.1. To set response headers, see How to use HTTP Headers in PHP.
Want me to talk about your product? You can sponsor this site.