phasync
Streams and files / MultipartStream

Class

MultipartStream

A multipart/form-data request body built from a nested array of fields.

Introduction#

Scalar and Stringable values become plain form fields. A resource (as returned by fopen()) or an \SplFileInfo becomes a file part, using its basename as the filename and mime_content_type() (falling back to application/octet-stream) as its content type. Nested arrays produce PHP-style bracketed field names, e.g. tags[0], tags[1].

The whole body is built lazily while it is read, but note that cURL reads the entire body into memory up front (via __toString()) before a request is sent, so this does not stream large uploads with bounded memory.

Class synopsis#

final class MultipartStream extends ComposableStream implements StreamInterface, \Stringable, MultipartStreamInterface {
    /* Methods */
    public MultipartStream::__construct(array $fields, ?string $boundary = null)
    public MultipartStream::getContentType(): string
    public MultipartStream::__toString(): string
    public MultipartStream::close(): void
    public MultipartStream::detach()
    public MultipartStream::getSize(): ?int
    public MultipartStream::tell(): int
    public MultipartStream::eof(): bool
    public MultipartStream::isSeekable(): bool
    public MultipartStream::seek($offset, $whence = SEEK_SET): void
    public MultipartStream::rewind(): void
    public MultipartStream::isWritable(): bool
    public MultipartStream::write($string): int
    public MultipartStream::isReadable(): bool
    public MultipartStream::read($length): string
    public MultipartStream::getContents(): string
    public MultipartStream::getMetadata($key = null)
}

Methods#

MethodDescription
__constructCreate the body from the fields.
getContentTypeReturn the Content-Type header value, multipart/form-data with this body's boundary.
__toStringReads all data from the stream into a string, from the beginning to end.
closeCloses the stream and any underlying resources.
detachSeparates any underlying resources from the stream.
getSizeGet the size of the stream if known.
tellReturns the current position of the file read/write pointer
eofReturns true if the stream is at the end of the stream.
isSeekableReturns whether or not the stream is seekable.
seekSeek to a position in the stream.
rewindSeek to the beginning of the stream.
isWritableReturns whether or not the stream is writable.
writeWrite data to the stream.
isReadableReturns whether or not the stream is readable.
readRead data from the stream.
getContentsReturns the remaining contents in a string
getMetadataGet stream metadata as an associative array or retrieve a specific key.

Examples#

Example 1Upload a file with form fields
use phasync\HttpClient\HttpClient;
use phasync\HttpClient\MultipartStream;

$base = require __DIR__ . '/../server.php';

$file = tmpfile();
fwrite($file, "id,name\n1,Ada\n");
rewind($file);

$body = new MultipartStream([
    'title'  => 'Customers',
    'tags'   => ['import', 'csv'],
    'upload' => $file,
], 'example-boundary');
echo $body->getContentType(), "\n";

$echo = json_decode((string) (new HttpClient())->post("$base/echo", $body)->getBody(), true);
echo json_encode($echo['form']), "\n";
echo 'file of ', $echo['files']['upload']['size'], " bytes\n";
Output
multipart/form-data; boundary=example-boundary
{"title":"Customers","tags":["import","csv"]}
file of 14 bytes
Example 2
$body = new MultipartStream([
    'title'      => 'My upload',
    'tags'       => ['a', 'b'],
    'attachment' => fopen('/path/to/file.txt', 'r'),
]);
$response = $client->post('https://example.com/upload', $body);

See also#