Skip to content

Server request

composer require quillstack/server-request

The request object based on PSR-7: Server Request.

A request built from what PHP hands the process — $_SERVER, $_GET, $_COOKIE, $_FILES and the body — and answered for the way PSR-7 says it should be. Every part of it is a parameter bag, so reading something which was not sent is an answer rather than a notice.

Requirements

  • PHP 8.1 or newer

Installation

shell
composer require quillstack/server-request

Usage

Building one from what arrived

php
$request = $factory->createServerRequest();

$request->getMethod();                    // 'GET'
$request->getUri()->getPath();            // '/users/42'
$request->getHeaderLine('accept');        // 'application/json'
$request->getRequestTarget();             // '/users/42?page=2'
$request->getQueryParams();               // ['page' => '2']
$request->getCookieParams();
$request->getParsedBody();

The query parameters come from $_GET rather than from the URI, which is what PSR-7 allows and what everything else in PHP does — so a rewritten URL and the parameters PHP parsed cannot disagree.

Attributes

What the router matched arrives here, and anything else a middleware wants to hand along:

php
$request = $request->withAttribute('id', '42');

$request->getAttribute('id');             // '42'
$request->getAttribute('page', '1');      // '1' — nothing under that name

Every change hands back a copy, so a middleware adding one does not change the request anybody else is holding.

A request class of your own

A controller can be handed a request of its own type, so what an endpoint expects is a class rather than a convention:

php
$factory->setRequestClass(UserRequest::class);

The class has to exist; UnknownServerRequestClassException says so when it does not.

Uploaded files

php
foreach ($request->getUploadedFiles() as $name => $file) {
    $file->getClientFilename();     // 'photo.jpg'
    $file->getClientMediaType();    // 'image/jpeg'
    $file->getSize();               // 20481
    $file->getError();              // UPLOAD_ERR_OK

    $file->moveTo('/var/www/uploads/photo.jpg');
}

A file can only be moved once — moving it again throws UploadedFileAlreadyMovedException, because the second call would otherwise fail in a way nobody expects. getStream() after a move throws for the same reason.

Technical documentation

ClassWhat it is
ServerRequestthe request, implementing Psr\Http\Message\ServerRequestInterface
Factory\ServerRequest\ServerRequestFactorybuilds one from given parameters
Factory\ServerRequest\ServerRequestFromGlobalsFactorybuilds one from what PHP was given
Factory\ServerRequest\GivenServerRequestFromGlobalsFactorythe same, as a named class
UploadedFiles\UploadedFileone uploaded file, implementing UploadedFileInterface
UploadedFiles\UploadedFileFactoryturns $_FILES into those
ExceptionThrown when
RequiredParamFromGlobalsNotFoundException$_SERVER is missing something a request needs
ServerRequestMethodNotKnownExceptionthe method is not one HTTP has
UnknownServerRequestClassExceptionthe request class named does not exist
ServerParamNotSetExceptiona parameter the factory was told to use is not there
UploadedFileNotUploadedExceptionthe file did not arrive as an upload
UploadedFileAlreadyMovedExceptionit has been moved once already
UploadedFileNotMovedExceptionmoving it failed

getRequestTarget() is the path and the query string, taken from the URI — the path is already an absolute one, so nothing is added to the front of it.

Unit tests

shell
composer test
composer test:coverage
composer stan

Docker

shell
docker-compose up -d
docker exec -w /var/www/html -it quillstack_server-request sh

License

MIT. See LICENSE.

Released under the MIT License.