php-http/multipart-stream-builder
Build multipart/form-data PSR-7 streams from fields and files, independent of any specific PSR-7 implementation. Useful for composing HTTP request bodies for uploads and complex forms, with easy integration via Composer in php-http based clients.
Install via Composer: composer require php-http/multipart-stream-builder. Since this package only builds multipart streams (and doesn’t include a PSR-7/17 implementation), ensure you have a compatible PSR-7/17 library installed (e.g., nyholm/psr7, guzzlehttp/psr7). The package uses php-http/discovery to auto-detect implementations.
First use case: Upload a file to an external service via multipart/form-data.
use Http\Message\MultipartStream\MultipartStreamBuilder;
$builder = new MultipartStreamBuilder();
$builder->addResource('file', fopen('/path/to/report.pdf', 'r'), [
'filename' => 'report.pdf',
'headers' => ['Content-Type' => 'application/pdf'],
]);
$stream = $builder->build();
$request = (new GuzzleHttp\Psr7\Request('POST', 'https://api.example.com/upload'))
->withHeader('Content-Type', 'multipart/form-data; boundary=' . $stream->getBoundary())
->withBody($stream);
reset() to clear internal state between batches (e.g., in Laravel queued jobs processing thousands of documents) — avoids memory leaks and repeated object instantiation.'mimetype' => 'application/vnd.apple.pkpass' for Apple Wallet passes, or use CustomMimetypeHelper for domain-specific types (e.g., application/x-fhir+json).addResource('tags', 'alpha'), addResource('tags', 'beta')) — critical for APIs like Salesforce that expect repeated keys.guzzlehttp/guzzle with php-http/guzzle6-adapter) to build clean, testable API clients.Content-Length headers: As of v1.4.0, per-part Content-Length headers are not added (RFC 7578 compliant). Most modern servers handle this, but legacy backends expecting explicit lengths may fail — inspect requests with tools like php-http/message-factory or curl -v.php://input or WebSocket streams work, but avoid mixing with large unbounded streams (e.g., real-time logs) without manual throttling — temp files may accumulate.basename() isn’t used: Filenames for data:// URIs or streams without names are omitted automatically; don’t rely on finfo_file() or pathinfo() to infer missing filenames..webp, .heic, and .msg are supported out-of-the-box, but obscure formats (e.g., .spx for SPARC binaries) require manual mimetype overrides.MultipartStreamBuilder to return a pre-generated fixture stream (e.g., store a sample multipart payload as a string and wrap it in a stream).getBoundary() matters: When sending manually, ensure the Content-Type header includes the exact boundary returned by $stream->getBoundary() — mismatched boundaries cause server-side parsing failures.How can I help you explore Laravel packages today?