11 KiB
PSR-7 Messages
This page covers the PSR-7 message objects provided by this package: requests, responses, server requests, uploaded files, and the message-specific header, URI, and body APIs. Use these objects when you need HTTP messages that can move between Guzzle, PSR-18 clients, PSR-15 middleware, and other PSR-7 compatible libraries.
HTTP requests and responses are both messages. A message has a start line, headers, and an optional body stream. Message and URI objects are immutable; methods named with*() return changed copies. Body streams are mutable handles, so reads and writes can change their cursor or contents. For body details, see Streams and Decorators. For URI helpers, see URI Helpers.
Creating Requests
You can create a request with GuzzleHttp\Psr7\Request.
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', 'https://example.com/users/123');
// You can provide optional headers and a body.
$headers = ['Accept' => 'application/json'];
$body = 'request body';
$request = new Request('PUT', 'https://example.com/users/123', $headers, $body);
Creating Responses
You can create a response with GuzzleHttp\Psr7\Response.
use GuzzleHttp\Psr7\Response;
// The constructor requires no arguments.
$response = new Response();
echo $response->getStatusCode();
// 200
echo $response->getProtocolVersion();
// 1.1
// You can provide a status, headers, body, and protocol version.
$response = new Response(200, ['Content-Type' => 'application/json'], '{"ok":true}', '1.1');
Creating Server Requests
Server requests represent incoming HTTP requests on the server side. They include the normal request method, URI, headers, and body, plus server parameters, cookies, query parameters, parsed body data, attributes, and uploaded files.
use GuzzleHttp\Psr7\ServerRequest;
$request = new ServerRequest('POST', 'https://example.com/form', [], 'name=Guzzle', '1.1', [
'REMOTE_ADDR' => '192.0.2.1',
]);
$request = $request
->withCookieParams(['session' => 'abc'])
->withQueryParams(['page' => '1'])
->withParsedBody(['name' => 'Guzzle'])
->withAttribute('route', 'profile');
echo $request->getServerParams()['REMOTE_ADDR'];
echo $request->getCookieParams()['session'];
echo $request->getQueryParams()['page'];
echo $request->getParsedBody()['name'];
echo $request->getAttribute('route');
Use ServerRequest::fromGlobals() to create a server request from PHP superglobals. It reads $_SERVER, $_GET, $_POST, $_COOKIE, and $_FILES, and attempts to include request headers when available.
use GuzzleHttp\Psr7\ServerRequest;
$request = ServerRequest::fromGlobals();
Use ServerRequest::getUriFromGlobals() when you only need the URI derived from $_SERVER.
use GuzzleHttp\Psr7\ServerRequest;
$uri = ServerRequest::getUriFromGlobals();
For URI construction and normalization helpers, see URI Helpers.
Requests
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', 'https://example.com/users/123', [
'Accept' => 'application/json',
]);
echo $request->getMethod();
echo $request->getUri();
PSR-7 messages are immutable. Methods such as withHeader() and withUri() return a modified copy.
$jsonRequest = $request->withHeader('Accept', 'application/json');
Responses
use GuzzleHttp\Psr7\Response;
$response = new Response(200, ['Content-Type' => 'application/json'], '{"ok":true}');
echo $response->getStatusCode();
echo $response->getHeaderLine('Content-Type');
echo $response->getBody();
URIs
use GuzzleHttp\Psr7\Uri;
$uri = new Uri('https://example.com/users?active=1');
echo $uri->getHost();
echo $uri->getQuery();
For URI-specific helper methods, see URI Helpers.
Headers
Both request and response messages contain HTTP headers.
Accessing Headers
You can check if a request or response has a specific header using hasHeader().
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', '/', ['X-Foo' => 'bar']);
if ($request->hasHeader('X-Foo')) {
echo 'It is there';
}
Retrieve all header values as an array of strings with getHeader().
$request->getHeader('X-Foo');
// ['bar']
// Missing headers return an empty array.
$request->getHeader('X-Bar');
// []
Iterate over the headers of a message with getHeaders().
foreach ($request->getHeaders() as $name => $values) {
echo $name . ': ' . implode(', ', $values) . "\r\n";
}
Complex Headers
Some headers contain additional key-value pair information. For example, Link headers contain a link and additional parameters:
<https://example.com/front.jpeg>; rel="front"; type="image/jpeg"
Use GuzzleHttp\Psr7\Header::parse() to parse these headers.
use GuzzleHttp\Psr7\Header;
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', '/', [
'Link' => '<https://example.com/front.jpeg>; rel="front"; type="image/jpeg"',
]);
$parsed = Header::parse($request->getHeader('Link'));
var_export($parsed);
This outputs:
array (
0 =>
array (
0 => '<https://example.com/front.jpeg>',
'rel' => 'front',
'type' => 'image/jpeg',
),
)
The result contains key-value pairs. Header values that have no key are indexed numerically, while header parts that form a key-value pair are added with their parameter name.
Body
Request and response bodies are Psr\Http\Message\StreamInterface instances. Streams are used for both uploading data and downloading data.
use GuzzleHttp\Psr7\Response;
$response = new Response(200, [], 'response body');
echo $response->getBody();
// response body
The body can be cast to a string, or you can read bytes from the stream as needed.
$body = $response->getBody();
echo $body->read(4);
$body->seek(0);
echo $body->getContents();
For more stream creation and decorator examples, see Streams and Decorators.
Uploaded Files
Uploaded files are represented by Psr\Http\Message\UploadedFileInterface instances. This package provides GuzzleHttp\Psr7\UploadedFile, which can wrap a local file path, PHP stream resource, or PSR-7 stream.
use GuzzleHttp\Psr7\UploadedFile;
use GuzzleHttp\Psr7\Utils;
$stream = Utils::streamFor('file contents');
$upload = new UploadedFile($stream, $stream->getSize(), UPLOAD_ERR_OK, 'example.txt', 'text/plain');
echo $upload->getClientFilename();
echo $upload->getClientMediaType();
echo $upload->getSize();
Call getStream() to read the uploaded content, or moveTo() to move or copy it to a target path. After moveTo() succeeds, isMoved() returns true, and calls that need the active upload stream will throw.
$body = $upload->getStream();
echo $body->getContents();
$upload->moveTo('/path/to/target.txt');
var_export($upload->isMoved());
// true
If the upload error code is not UPLOAD_ERR_OK, the object still exposes getError(), getSize(), getClientFilename(), and getClientMediaType(), but getStream() and moveTo() throw because no successful upload content is available.
ServerRequest::normalizeFiles() converts a $_FILES-style array into a tree of uploaded file instances. It accepts simple file specs, nested PHP $_FILES shapes, existing UploadedFileInterface instances, and nested arrays of uploaded files.
use GuzzleHttp\Psr7\ServerRequest;
$files = ServerRequest::normalizeFiles([
'avatar' => [
'tmp_name' => '/tmp/php123',
'size' => 1024,
'error' => UPLOAD_ERR_OK,
'name' => 'avatar.png',
'type' => 'image/png',
],
'photos' => [
'tmp_name' => [
'first' => '/tmp/php456',
],
'size' => [
'first' => 2048,
],
'error' => [
'first' => UPLOAD_ERR_OK,
],
'name' => [
'first' => 'photo.jpg',
],
'type' => [
'first' => 'image/jpeg',
],
],
]);
$request = (new ServerRequest('POST', '/upload'))->withUploadedFiles($files);
HTTP Method Casing
HTTP method names are case-sensitive in PSR-7. Requests created explicitly with
Request, ServerRequest, withMethod(), Message::parseRequest(), or the
PSR-17 factories preserve the method string as provided. ServerRequest::fromGlobals()
normalizes $_SERVER['REQUEST_METHOD'] to uppercase for compatibility when
hydrating requests from PHP server globals.
Request Methods
When creating a request, provide the HTTP method you want to perform. You can specify any method, including custom methods that are not part of RFC 9110.
use GuzzleHttp\Psr7\Request;
$request = new Request('MOVE', 'https://example.com/resource');
echo $request->getMethod();
// MOVE
Request URI
The request URI is represented by a Psr\Http\Message\UriInterface object. This package provides an implementation through GuzzleHttp\Psr7\Uri.
When creating a request, you can provide the URI as a string or as a UriInterface instance.
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
$request = new Request('GET', new Uri('https://example.com/users?id=123'));
Scheme
The scheme specifies the protocol. For HTTP requests, this is usually http or https.
$request = new Request('GET', 'https://example.com');
echo $request->getUri()->getScheme();
// https
Host
The host is accessible from the URI and is also represented by the Host header.
$request = new Request('GET', 'https://example.com');
echo $request->getUri()->getHost();
// example.com
echo $request->getHeaderLine('Host');
// example.com
Port
No port is necessary for the default http and https ports.
$request = new Request('GET', 'https://example.com:8443');
echo $request->getUri()->getPort();
// 8443
Path
The request path is accessible through the URI object.
$request = new Request('GET', 'https://example.com/users/123');
echo $request->getUri()->getPath();
// /users/123
Characters that are not allowed in a URI path are percent-encoded according to RFC 3986 section 3.3.
Query String
The query string is accessible through the URI object.
$request = new Request('GET', 'https://example.com/?foo=bar');
echo $request->getUri()->getQuery();
// foo=bar
Characters that are not allowed in a URI query are percent-encoded according to RFC 3986 section 3.4.
Response Status
Responses expose the status code, reason phrase, and protocol version.
use GuzzleHttp\Psr7\Response;
$response = new Response(200, [], 'OK');
echo $response->getStatusCode();
// 200
echo $response->getReasonPhrase();
// OK
echo $response->getProtocolVersion();
// 1.1