guzzlehttp/psr7
Full PSR-7 message implementation with rich stream support: multiple stream types and decorators (append, buffer, caching, etc.), plus helpers like query-string parsing. Installed via Composer and maintained with v2 for PHP 7.2.5+.
Installation:
composer require guzzlehttp/psr7
Ensure your composer.json targets PHP 7.2.5+ (for v2.x).
First Use Case: Create a PSR-7 request/response with minimal boilerplate:
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
$request = new Request('GET', 'https://api.example.com/data');
$response = new Response(200, [], '{"status": "success"}');
Key Entry Points:
Utils::streamFor(): Convert strings/resources to streams.Message::toString(): Debug HTTP messages.AppendStream, LimitStream) for common operations.Request/Response Handling:
// Build a request with headers/body
$request = new Request('POST', '/upload', [
'Content-Type' => 'application/json',
], json_encode(['file' => 'data.txt']));
// Parse a raw response
$response = Message::parseResponse($rawHttpString);
Stream Manipulation:
$stream = new AppendStream([
Utils::streamFor('Part 1'),
Utils::streamFor('Part 2'),
]);
$fileStream = Utils::streamFor(fopen('large_file.zip', 'r'));
$chunked = new LimitStream($fileStream, 1024 * 1024); // 1MB chunks
Query/URI Utilities:
// Parse query strings
$params = Query::parse('foo=bar&baz[]=1&baz[]=2');
// Build URIs
$uri = Message::parseRequestUri('/search', ['query' => 'q=test']);
Debugging/Inspection:
// Log request/response details
echo Message::toString($request);
echo Message::bodySummary($response); // Truncated body preview
$client = new \GuzzleHttp\Client();
$response = $client->send($request, ['http_errors' => false]);
$fileStream = new LazyOpenStream('/path/to/file', 'r');
$request = new Request('PUT', '/upload', [], $fileStream);
$stream = new InflateStream(
new LoggingStream($originalStream, fn($data) => logger($data))
);
Stream Ownership:
fclose()) does not close the stream. Use StreamInterface::close() explicitly.$stream->close() when done.Non-Seekable Streams:
CachingStream or LimitStream may fail on non-seekable streams (e.g., sockets, php://input).CachingStream if seeking is needed:
$stream = new CachingStream(fopen('php://input', 'r'));
Memory Leaks:
BufferStream/CachingStream hold data in memory. Avoid large buffers in long-running processes.DroppingStream or LimitStream to cap memory usage.Query String Parsing:
Query::parse() does not handle nested arrays (e.g., foo[bar]=1 becomes 'foo[bar]').http_build_query() for nested data.Deprecated Methods:
Header::normalize() is deprecated. Use Header::splitList() instead.$metadata = $stream->getMetadata();
var_dump($metadata['seekable'], $metadata['readable']);
if ($stream->eof()) {
// Handle end-of-stream
}
read()/write() in a custom decorator to log calls:
class DebugStream implements StreamInterface {
use StreamDecoratorTrait;
public function read($length) {
echo "Reading {$length} bytes...\n";
return $this->stream->read($length);
}
}
Custom Stream Decorators:
Use StreamDecoratorTrait to create lightweight decorators:
class TimingStream implements StreamInterface {
use StreamDecoratorTrait;
private $start;
public function read($length) {
$this->start ??= microtime(true);
return $this->stream->read($length);
}
public function getReadTime() {
return microtime(true) - $this->start;
}
}
Stream Wrapper: Convert PSR-7 streams to PHP resources for interop:
$resource = StreamWrapper::getResource($stream);
$data = fread($resource, 1024);
Query/URI Utilities:
Extend Query::build() for custom encoding (e.g., RFC 3986 vs. default):
$query = Query::build(['page' => 1], PHP_QUERY_RFC3986);
Message Modification:
Use Utils::modifyRequest() to avoid deep cloning:
$modified = Utils::modifyRequest($request, [
'set_headers' => ['Authorization' => 'Bearer token'],
'body' => Utils::streamFor('new body'),
]);
Utils::copyToString():
Avoid for large streams (>1MB). Use Utils::copyToStream() with a file stream instead.AppendStream:
Seeking is not supported. Use LimitStream for random access.PumpStream:
Callables must return false on EOF. Omitting this can cause hangs.How can I help you explore Laravel packages today?