Handling HTTP requests in PHP

By

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:

PHP Variables table showing $_SERVER superglobal values including HTTP_HOST, HTTP_USER_AGENT, SERVER_NAME and other server configuration data

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

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.

Related posts about php: