guzzlehttp/psr7
Full PSR-7 HTTP message implementation from Guzzle: request/response objects, URI and stream support, plus stream decorators (buffering, caching, appending, dropping) and utilities like query string parsing. Composer install; v2 supports PHP 7.2.5–8.5.
Installation:
composer require guzzlehttp/psr7
Add to composer.json under require or require-dev depending on your needs.
First Use Case: Create a basic HTTP request/response using PSR-7 messages:
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
$request = new Request('GET', 'https://example.com');
$response = new Response(200, [], 'Hello, World!');
Key Classes to Know:
Request, Response: Core PSR-7 message interfaces.StreamInterface: For handling request/response bodies.Utils: Static helper methods (e.g., streamFor, copyToString).Where to Look First:
GuzzleHttp\Psr7\Utils for utility methods (e.g., stream creation, query parsing).AppendStream, LimitStream) for advanced use cases.$request = new Request('POST', '/api/users', [
'Content-Type' => 'application/json',
], json_encode(['name' => 'John']));
$response = new Response(201, [], json_encode(['id' => 123]));
$stream = Utils::streamFor('Hello');
$fileStream = Utils::streamFor(fopen('file.txt', 'r'));
$limitedStream = new LimitStream($stream, 100); // Read first 100 bytes
$appendedStream = new AppendStream([$stream1, $stream2]);
Utils::copyToString($stream); // Convert stream to string
Utils::copyToStream($source, $destination); // Stream-to-stream copy
$query = Query::parse('foo=bar&baz=qux');
// ['foo' => 'bar', 'baz' => 'qux']
$queryString = Query::build(['foo' => 'bar', 'baz' => 'qux']);
// 'foo=bar&baz=qux'
$modified = Utils::modifyRequest($request, [
'method' => 'PUT',
'set_headers' => ['X-Custom' => 'Value'],
]);
$hash = Utils::hash($stream, 'md5');
Utils::rewindBody($response);
HTTP Clients (Guzzle Integration):
guzzlehttp/psr7 with Laravel's HTTP client (e.g., Http::asJson()) for custom request/response handling.$response = Http::withOptions(['decode_content' => false])->get('...');
$stream = $response->getBody();
File Uploads/Downloads:
LazyOpenStream for lazy file handling:
$stream = new LazyOpenStream(storage_path('file.txt'), 'r');
LimitStream for chunked uploads:
$chunkedStream = new LimitStream($fileStream, 1024 * 1024); // 1MB chunks
Middleware:
$kernel->pushMiddleware(function ($request, $next) {
$request = Utils::modifyRequest($request, [
'set_headers' => ['X-Processed' => 'true'],
]);
return $next($request);
});
Testing:
$mockStream = $this->createMock(StreamInterface::class);
$mockStream->method('read')->willReturn('mocked');
$request = new Request('GET', '/', [], $mockStream);
API Responses:
Illuminate\Http\Response:
$psrResponse = new Response(200, [], '{"data": "..."}');
return response($psrResponse->getBody(), $psrResponse->getStatusCode(), $psrResponse->getHeaders());
Stream Ownership:
$stream->close()) may break decorators or upstream consumers.NoSeekStream or CachingStream to manage lifecycle explicitly.Memory Leaks:
CachingStream buffers data in memory/disk. Large streams can exhaust resources.highWaterMark or use LimitStream to cap size.Seekable vs. Non-Seekable Streams:
PumpStream, FnStream) are non-seekable. Operations like seek() or rewind() will fail.CachingStream to wrap non-seekable streams or avoid seeking.Query Parsing Quirks:
Query::parse() does not handle nested arrays (e.g., foo[a]=1&foo[b]=2 becomes ['foo[a]' => '1']).http_build_query() for nested structures.Stream Decorator Order:
$stream = new LimitStream(new CachingStream($originalStream), 1024);
UTF-8 Assumptions:
readLine) assume UTF-8 encoding. Non-UTF-8 streams may break.$utf8Stream = new TransformStream($stream, 'iconv', 'ISO-8859-1//TRANSLIT//IGNORE', 'UTF-8');
PHP Stream Resource Lifecycle:
fopen) in PSR-7 streams requires manual cleanup.LazyOpenStream or ensure resources are closed:
$stream = Utils::streamFor(fopen('file.txt', 'r'));
// ... use stream ...
fclose($stream->detach());
Stream Inspection:
var_dump($stream->getMetadata());
echo $stream->getSize(), ' | ', $stream->tell();
Logging Stream Content:
Utils::copyToString() to inspect content:
$content = Utils::copyToString($stream);
\Log::debug('Stream content:', ['content' => $content]);
Decorator Debugging:
FnStream for debugging:
$debugStream = FnStream::decorate($stream, [
'read' => function ($length) use ($stream) {
\Log::debug('Reading', ['length' => $length]);
return $stream->read($length);
},
]);
Common Exceptions:
RuntimeException: Thrown for invalid operations (e.g., seeking on non-seekable streams).InvalidArgumentException: Invalid input to utilities (e.g., Query::parse).StreamDecoratorTrait for reusable decorators:
class LoggingStream implements StreamInterface {
use StreamDecoratorTrait;
public function
How can I help you explore Laravel packages today?