Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Nyholm Psr7
https://github.com/nyholm/psr7
Admin
Nyholm Psr7 is a super lightweight, strict, and fast PSR-7 implementation for PHP with complete
...
Tokens:
7,301
Snippets:
43
Trust Score:
10
Update:
1 week ago
Context
Skills
Chat
Benchmark
95.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Nyholm PSR-7 Nyholm PSR-7 is a super lightweight, strict, and fast implementation of the PSR-7 HTTP message interfaces and PSR-17 HTTP factories for PHP. With only around 1,000 lines of code, it is the smallest PSR-7 implementation available while maintaining 100% compliance with the PSR-7 specification and outperforming other implementations like Guzzle, Laminas, and Slim in benchmarks. The library provides all the essential HTTP message abstractions needed for modern PHP applications: Request, Response, ServerRequest, Stream, UploadedFile, and Uri objects. It implements both PSR-7 (HTTP Message interfaces) and PSR-17 (HTTP Factories) standards, making it compatible with any PSR-7 compliant HTTP client or framework. The single `Psr17Factory` class serves as the unified factory for creating all PSR-7 objects. ## Installation Install the library via Composer: ```bash composer require nyholm/psr7 ``` ## Psr17Factory - Create HTTP Objects The `Psr17Factory` is the main entry point for creating all PSR-7 objects. It implements all PSR-17 factory interfaces including `RequestFactoryInterface`, `ResponseFactoryInterface`, `ServerRequestFactoryInterface`, `StreamFactoryInterface`, `UploadedFileFactoryInterface`, and `UriFactoryInterface`. ```php <?php use Nyholm\Psr7\Factory\Psr17Factory; $factory = new Psr17Factory(); // Create a GET request $request = $factory->createRequest('GET', 'https://api.example.com/users'); // Create a POST request with headers and body $postRequest = $factory->createRequest('POST', 'https://api.example.com/users'); $postRequest = $postRequest ->withHeader('Content-Type', 'application/json') ->withHeader('Authorization', 'Bearer token123') ->withBody($factory->createStream('{"name": "John", "email": "john@example.com"}')); // Create a response $response = $factory->createResponse(200, 'OK'); $response = $response ->withHeader('Content-Type', 'application/json') ->withBody($factory->createStream('{"status": "success"}')); // Create a URI $uri = $factory->createUri('https://user:pass@example.com:8080/path?query=value#fragment'); // Create a stream from string $stream = $factory->createStream('Hello, World!'); // Create a stream from file $fileStream = $factory->createStreamFromFile('/path/to/file.txt', 'r'); // Create a stream from resource $resource = fopen('php://temp', 'r+'); fwrite($resource, 'data'); rewind($resource); $resourceStream = $factory->createStreamFromResource($resource); // Create a server request $serverRequest = $factory->createServerRequest('GET', '/api/users', $_SERVER); // Create an uploaded file $uploadedFile = $factory->createUploadedFile( $factory->createStream('file contents'), 1024, // size in bytes UPLOAD_ERR_OK, // upload error status 'document.pdf', // client filename 'application/pdf' // client media type ); ``` ## Request - HTTP Client Request The `Request` class represents an outgoing HTTP request. It implements `Psr\Http\Message\RequestInterface` and provides immutable methods for building requests with method, URI, headers, and body. ```php <?php use Nyholm\Psr7\Request; use Nyholm\Psr7\Uri; use Nyholm\Psr7\Stream; // Create a simple GET request $request = new Request('GET', 'https://api.example.com/users'); // Create a POST request with all options $request = new Request( 'POST', // HTTP method 'https://api.example.com/users', // URI (string or UriInterface) ['Content-Type' => 'application/json'], // Headers array '{"name": "John"}', // Body (string, resource, or StreamInterface) '1.1' // Protocol version ); // Get request properties echo $request->getMethod(); // "POST" echo $request->getUri(); // "https://api.example.com/users" echo $request->getRequestTarget(); // "/users" echo $request->getProtocolVersion(); // "1.1" // Work with headers $request = $request->withHeader('Accept', 'application/json'); $request = $request->withAddedHeader('Accept', 'text/html'); // Adds to existing values echo $request->getHeaderLine('Accept'); // "application/json, text/html" print_r($request->getHeader('Accept')); // ["application/json", "text/html"] $request = $request->withoutHeader('Accept'); // Modify the request (immutable - returns new instance) $newRequest = $request ->withMethod('PUT') ->withUri(new Uri('https://api.example.com/users/123')) ->withHeader('Authorization', 'Bearer abc123') ->withBody(Stream::create('{"name": "Jane"}')); // Check if header exists if ($request->hasHeader('Content-Type')) { echo $request->getHeaderLine('Content-Type'); } ``` ## Response - HTTP Response The `Response` class represents an HTTP response. It implements `Psr\Http\Message\ResponseInterface` with automatic status code reason phrase mapping for all standard HTTP status codes. ```php <?php use Nyholm\Psr7\Response; use Nyholm\Psr7\Stream; // Create a simple 200 OK response $response = new Response(); // Default: 200 OK // Create response with all options $response = new Response( 201, // Status code ['Content-Type' => 'application/json'], // Headers '{"id": 1, "name": "John"}', // Body '1.1', // Protocol version 'Created' // Reason phrase (optional, auto-detected) ); // Get response properties echo $response->getStatusCode(); // 201 echo $response->getReasonPhrase(); // "Created" echo $response->getBody(); // '{"id": 1, "name": "John"}' // Common HTTP responses $okResponse = new Response(200); // "OK" $createdResponse = new Response(201); // "Created" $noContentResponse = new Response(204); // "No Content" $redirectResponse = new Response(302); // "Found" $notFoundResponse = new Response(404); // "Not Found" $serverErrorResponse = new Response(500); // "Internal Server Error" // Modify response (immutable) $response = (new Response()) ->withStatus(200) ->withHeader('Content-Type', 'text/html') ->withHeader('Cache-Control', 'no-cache') ->withBody(Stream::create('<html><body>Hello!</body></html>')); // Change status code with custom reason phrase $response = $response->withStatus(418, "I'm a teapot"); echo $response->getReasonPhrase(); // "I'm a teapot" // JSON API response example $jsonResponse = (new Response(200)) ->withHeader('Content-Type', 'application/json') ->withBody(Stream::create(json_encode([ 'status' => 'success', 'data' => ['id' => 1, 'name' => 'John'] ]))); ``` ## ServerRequest - Server-Side Request The `ServerRequest` class represents an incoming HTTP request on the server side. It implements `Psr\Http\Message\ServerRequestInterface` with support for server parameters, cookies, query parameters, uploaded files, and request attributes. ```php <?php use Nyholm\Psr7\ServerRequest; use Nyholm\Psr7\UploadedFile; use Nyholm\Psr7\Stream; // Create a server request $request = new ServerRequest( 'POST', // Method 'https://example.com/api/users?page=1', // URI ['Content-Type' => 'application/json'], // Headers '{"name": "John"}', // Body '1.1', // Protocol version ['REMOTE_ADDR' => '192.168.1.1', 'SERVER_NAME' => 'example.com'] // Server params ); // Query parameters are automatically parsed from URI print_r($request->getQueryParams()); // ['page' => '1'] // Get server parameters $serverParams = $request->getServerParams(); echo $serverParams['REMOTE_ADDR']; // "192.168.1.1" // Work with cookies $request = $request->withCookieParams([ 'session_id' => 'abc123', 'user_pref' => 'dark_mode' ]); $cookies = $request->getCookieParams(); echo $cookies['session_id']; // "abc123" // Work with query parameters $request = $request->withQueryParams(['page' => '2', 'limit' => '10']); $params = $request->getQueryParams(); echo $params['limit']; // "10" // Work with parsed body (for POST data) $request = $request->withParsedBody([ 'username' => 'john', 'email' => 'john@example.com' ]); $data = $request->getParsedBody(); echo $data['username']; // "john" // Work with uploaded files $uploadedFile = new UploadedFile( Stream::create('file content'), 12, UPLOAD_ERR_OK, 'document.pdf', 'application/pdf' ); $request = $request->withUploadedFiles(['document' => $uploadedFile]); $files = $request->getUploadedFiles(); // Work with attributes (commonly used for routing parameters) $request = $request->withAttribute('user_id', 123); $request = $request->withAttribute('route', 'api.users.show'); $userId = $request->getAttribute('user_id'); // 123 $default = $request->getAttribute('missing', 'none'); // "none" $allAttributes = $request->getAttributes(); // ['user_id' => 123, 'route' => ...] $request = $request->withoutAttribute('route'); ``` ## Stream - Message Body Stream The `Stream` class represents a data stream for HTTP message bodies. It implements `Psr\Http\Message\StreamInterface` and can be created from strings, resources, or existing stream instances. For large strings (200KB+), it uses an optimized copy-on-write mechanism. ```php <?php use Nyholm\Psr7\Stream; // Create stream from string $stream = Stream::create('Hello, World!'); echo $stream->getContents(); // "Hello, World!" // Create stream from resource $resource = fopen('php://temp', 'r+'); fwrite($resource, 'Resource content'); rewind($resource); $stream = Stream::create($resource); // Create stream from file resource $fileResource = fopen('/path/to/file.txt', 'r'); $stream = new Stream($fileResource); // Read stream contents $stream = Stream::create('Hello, World!'); echo $stream; // "Hello, World!" (via __toString) echo $stream->getSize(); // 13 echo $stream->tell(); // 0 (current position) echo $stream->read(5); // "Hello" echo $stream->tell(); // 5 echo $stream->getContents(); // ", World!" (reads remaining) echo $stream->eof(); // true // Seek and rewind $stream->rewind(); // Go back to start $stream->seek(7); // Move to position 7 echo $stream->read(5); // "World" // Write to stream $stream = Stream::create(''); $stream->write('First line'); $stream->write(' - Second part'); $stream->rewind(); echo $stream->getContents(); // "First line - Second part" // Check stream capabilities $stream = Stream::create('test'); echo $stream->isReadable(); // true echo $stream->isWritable(); // true echo $stream->isSeekable(); // true // Get stream metadata $meta = $stream->getMetadata(); echo $stream->getMetadata('mode'); // "r+" echo $stream->getMetadata('uri'); // "php://memory" // Detach underlying resource $resource = $stream->detach(); // Returns resource, stream becomes unusable // $stream->read(1); // Would throw RuntimeException // Close stream $stream = Stream::create('test'); $stream->close(); // Releases the resource ``` ## Uri - URI Manipulation The `Uri` class represents a URI according to RFC 3986. It implements `Psr\Http\Message\UriInterface` with full support for all URI components including scheme, user info, host, port, path, query, and fragment. ```php <?php use Nyholm\Psr7\Uri; // Create URI from string $uri = new Uri('https://user:pass@example.com:8080/path/to/resource?foo=bar&baz=qux#section'); // Get URI components echo $uri->getScheme(); // "https" echo $uri->getHost(); // "example.com" echo $uri->getPort(); // 8080 echo $uri->getUserInfo(); // "user:pass" echo $uri->getAuthority(); // "user:pass@example.com:8080" echo $uri->getPath(); // "/path/to/resource" echo $uri->getQuery(); // "foo=bar&baz=qux" echo $uri->getFragment(); // "section" echo (string) $uri; // Full URI string // Standard ports (80 for http, 443 for https) return null $stdUri = new Uri('https://example.com:443/path'); echo $stdUri->getPort(); // null (standard port is suppressed) $nonStdUri = new Uri('https://example.com:8443/path'); echo $nonStdUri->getPort(); // 8443 (non-standard port) // Build URI using fluent interface (immutable) $uri = (new Uri()) ->withScheme('https') ->withHost('api.example.com') ->withPort(8080) ->withPath('/v1/users') ->withQuery('active=true&role=admin') ->withFragment('top'); echo $uri; // "https://api.example.com:8080/v1/users?active=true&role=admin#top" // Modify existing URI $uri = new Uri('https://example.com/users'); $newUri = $uri ->withPath('/users/123') ->withQuery('fields=name,email'); echo $newUri; // "https://example.com/users/123?fields=name,email" // URI with user info $uri = (new Uri('https://example.com')) ->withUserInfo('username', 'password'); echo $uri->getAuthority(); // "username:password@example.com" // Empty URI $emptyUri = new Uri(); echo $emptyUri->getHost(); // "" echo $emptyUri->getPath(); // "" ``` ## UploadedFile - File Upload Handling The `UploadedFile` class represents an uploaded file. It implements `Psr\Http\Message\UploadedFileInterface` and provides methods to access file metadata and move uploaded files to a target location. ```php <?php use Nyholm\Psr7\UploadedFile; use Nyholm\Psr7\Stream; // Create uploaded file from stream $stream = Stream::create('PDF file contents...'); $uploadedFile = new UploadedFile( $stream, // Stream or file path or resource 1024, // Size in bytes UPLOAD_ERR_OK, // Upload error code 'document.pdf', // Client filename 'application/pdf' // Client media type ); // Get file information echo $uploadedFile->getSize(); // 1024 echo $uploadedFile->getError(); // 0 (UPLOAD_ERR_OK) echo $uploadedFile->getClientFilename(); // "document.pdf" echo $uploadedFile->getClientMediaType(); // "application/pdf" // Get stream for reading $stream = $uploadedFile->getStream(); $contents = $stream->getContents(); // Move file to target location $uploadedFile->moveTo('/var/uploads/document.pdf'); // After moving, getStream() will throw RuntimeException // Handle upload errors $errorCodes = [ UPLOAD_ERR_OK => 'No error', UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize', UPLOAD_ERR_FORM_SIZE => 'File exceeds MAX_FILE_SIZE in form', UPLOAD_ERR_PARTIAL => 'File only partially uploaded', UPLOAD_ERR_NO_FILE => 'No file uploaded', UPLOAD_ERR_NO_TMP_DIR => 'Missing temp directory', UPLOAD_ERR_CANT_WRITE => 'Failed to write to disk', UPLOAD_ERR_EXTENSION => 'Upload stopped by extension', ]; // Create uploaded file with error $failedUpload = new UploadedFile( Stream::create(''), 0, UPLOAD_ERR_INI_SIZE, 'large-file.zip', 'application/zip' ); if ($failedUpload->getError() !== UPLOAD_ERR_OK) { echo "Upload failed: " . $errorCodes[$failedUpload->getError()]; } // Create from file path (for CLI/testing) $uploadedFile = new UploadedFile( '/tmp/phpXXXXXX', // Temp file path filesize('/tmp/phpXXXXXX'), UPLOAD_ERR_OK, 'upload.jpg', 'image/jpeg' ); ``` ## Integration with HTTP Clients The library integrates with PSR-18 HTTP clients like Buzz, Guzzle, and Symfony HTTP Client. Here is an example showing how to send HTTP requests using nyholm/psr7 with an HTTP client. ```php <?php use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7\Request; use Buzz\Client\Curl; // Using with Buzz HTTP client // composer require kriswallsmith/buzz $factory = new Psr17Factory(); $client = new Curl($factory); // Send GET request $request = $factory->createRequest('GET', 'https://api.example.com/users'); $response = $client->sendRequest($request); echo $response->getStatusCode(); // 200 echo $response->getBody(); // Response body // Send POST request with JSON body $request = $factory->createRequest('POST', 'https://api.example.com/users') ->withHeader('Content-Type', 'application/json') ->withHeader('Accept', 'application/json') ->withBody($factory->createStream(json_encode([ 'name' => 'John Doe', 'email' => 'john@example.com' ]))); $response = $client->sendRequest($request); $data = json_decode($response->getBody()->getContents(), true); // Send request with authentication $request = $factory->createRequest('GET', 'https://api.example.com/protected') ->withHeader('Authorization', 'Bearer your-api-token'); $response = $client->sendRequest($request); // Handle response if ($response->getStatusCode() === 200) { $contentType = $response->getHeaderLine('Content-Type'); $body = $response->getBody()->getContents(); if (str_contains($contentType, 'application/json')) { $data = json_decode($body, true); } } ``` ## Server Request Creation from Globals For handling incoming HTTP requests in a server context, use the `nyholm/psr7-server` companion package to create ServerRequest objects from PHP superglobals. ```php <?php // composer require nyholm/psr7-server use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7Server\ServerRequestCreator; $factory = new Psr17Factory(); $creator = new ServerRequestCreator( $factory, // ServerRequestFactory $factory, // UriFactory $factory, // UploadedFileFactory $factory // StreamFactory ); // Create server request from PHP superglobals $serverRequest = $creator->fromGlobals(); // Access request data $method = $serverRequest->getMethod(); // "POST" $uri = $serverRequest->getUri(); // UriInterface $headers = $serverRequest->getHeaders(); // All headers $body = $serverRequest->getBody(); // StreamInterface $queryParams = $serverRequest->getQueryParams(); // $_GET equivalent $parsedBody = $serverRequest->getParsedBody(); // $_POST equivalent $uploadedFiles = $serverRequest->getUploadedFiles(); // Normalized $_FILES $cookies = $serverRequest->getCookieParams(); // $_COOKIE equivalent $serverParams = $serverRequest->getServerParams(); // $_SERVER // Example: Simple router $path = $serverRequest->getUri()->getPath(); $method = $serverRequest->getMethod(); if ($method === 'GET' && $path === '/api/users') { // Handle GET /api/users } elseif ($method === 'POST' && $path === '/api/users') { $data = json_decode($serverRequest->getBody()->getContents(), true); // Handle POST /api/users } ``` ## Emitting Responses To send HTTP responses to the client, use a response emitter like the one from `laminas/laminas-httphandlerrunner`. ```php <?php // composer require laminas/laminas-httphandlerrunner use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7\Response; use Laminas\HttpHandlerRunner\Emitter\SapiEmitter; $factory = new Psr17Factory(); $emitter = new SapiEmitter(); // Simple text response $response = $factory->createResponse(200) ->withHeader('Content-Type', 'text/plain') ->withBody($factory->createStream('Hello, World!')); $emitter->emit($response); // JSON API response $data = ['status' => 'success', 'data' => ['id' => 1, 'name' => 'John']]; $response = $factory->createResponse(200) ->withHeader('Content-Type', 'application/json') ->withBody($factory->createStream(json_encode($data))); $emitter->emit($response); // Redirect response $response = $factory->createResponse(302) ->withHeader('Location', 'https://example.com/login'); $emitter->emit($response); // Error response $response = $factory->createResponse(404) ->withHeader('Content-Type', 'application/json') ->withBody($factory->createStream(json_encode([ 'error' => 'Not Found', 'message' => 'The requested resource was not found' ]))); $emitter->emit($response); // File download response $fileStream = $factory->createStreamFromFile('/path/to/document.pdf', 'r'); $response = $factory->createResponse(200) ->withHeader('Content-Type', 'application/pdf') ->withHeader('Content-Disposition', 'attachment; filename="document.pdf"') ->withHeader('Content-Length', (string) $fileStream->getSize()) ->withBody($fileStream); $emitter->emit($response); ``` ## Summary Nyholm PSR-7 is ideal for applications requiring PSR-7 compliance with minimal overhead. Common use cases include building RESTful APIs, middleware-based applications, and HTTP client implementations. The library works seamlessly with frameworks like Slim, Mezzio, and any PSR-15 middleware stack. Its strict adherence to PSR-7 and PSR-17 specifications ensures maximum interoperability with the PHP ecosystem. Integration patterns typically involve using `Psr17Factory` as the central factory for all HTTP message creation, combining with `nyholm/psr7-server` for incoming request handling, and using a PSR-18 HTTP client for outgoing requests. The immutable design of all classes promotes functional programming patterns and thread safety. For production deployments, the library's small footprint and high performance make it an excellent choice for microservices and high-throughput applications.