Skip to content

Creating requests from global state

Greg Bowler edited this page Apr 24, 2026 · 2 revisions

On the server, we rarely start with a fully formed request object. We usually start with PHP globals such as $_SERVER, $_FILES, $_GET, and $_POST.

GT\Http\RequestFactory exists to bridge that gap.

Why use a factory?

The factory keeps the messy parts of request construction in one place:

  • request method validation
  • URI construction
  • header extraction from $_SERVER
  • body stream creation
  • uploaded file and form/query data wiring

That means the rest of the application can receive one ServerRequest object instead of several unrelated arrays.

Build a ServerRequest

use GT\Http\RequestFactory;

$request = new RequestFactory()
	->createServerRequestFromGlobalState(
		$_SERVER,
		$_FILES,
		$_GET,
		$_POST
	);

The returned object implements Psr\Http\Message\ServerRequestInterface.

What the factory reads

RequestFactory uses the incoming arrays like this:

  • $_SERVER["REQUEST_METHOD"] becomes the request method.
  • $_SERVER["REQUEST_URI"], HTTP_HOST, SERVER_PORT, HTTPS, and QUERY_STRING contribute to the URI.
  • $_SERVER["HTTP_*"] entries become request headers.
  • the input stream becomes the request body stream.
  • $_FILES, $_GET, and $_POST are attached to the ServerRequest.

A closer look

use GT\Http\RequestFactory;

$factory = new RequestFactory();

$request = $factory->createServerRequestFromGlobalState(
	[
		"REQUEST_METHOD" => "POST",
		"REQUEST_URI" => "/profile/update",
		"HTTP_HOST" => "example.com",
		"SERVER_PORT" => "443",
		"HTTPS" => "on",
		"HTTP_ACCEPT" => "text/html",
		"SERVER_PROTOCOL" => "HTTP/1.1",
	],
	[],
	["tab" => "security"],
	["email" => "dev@example.com"]
);

echo $request->getMethod();           // POST
echo $request->getUri();              // https://example.com/profile/update?tab=security
echo $request->getHeaderLine("Accept"); // text/html

Header names from $_SERVER

The factory converts HTTP_* entries into header names by removing the prefix and replacing underscores with hyphens.

For example:

  • HTTP_ACCEPT_LANGUAGE becomes ACCEPT-LANGUAGE
  • HTTP_X_FORWARDED_FOR becomes X-FORWARDED-FOR

Headers remain case-insensitive when you read them through the request object.

Body stream input

By default the factory reads from php://input, which matches normal PHP request handling.

For tests or specialised scripts, you can override the body input path:

$request = $factory->createServerRequestFromGlobalState(
	$_SERVER,
	$_FILES,
	$_GET,
	$_POST,
	"/tmp/request-body.txt"
);

Validation

If the request method is missing or invalid, the factory throws InvalidRequestMethodHttpException.

That is a good thing. It means broken request state is rejected early, rather than silently spreading through the application.

Note

In WebEngine, this factory is handled automatically during application start-up. Applications using WebEngine receive an already-built request object rather than calling RequestFactory directly.


Now that the request exists, the next step is to understand the objects you will read from most often: Request and ServerRequest objects.

Clone this wiki locally