class MultipartStream
Stream that when read returns bytes for a streaming multipart or multipart/form-data stream.
Hierarchy
- class \GuzzleHttp\Psr7\MultipartStream implements \Psr\Http\Message\StreamInterface uses \GuzzleHttp\Psr7\StreamDecoratorTrait
Expanded class hierarchy of MultipartStream
File
-
vendor/
guzzlehttp/ psr7/ src/ MultipartStream.php, line 13
Namespace
GuzzleHttp\Psr7View source
final class MultipartStream implements StreamInterface {
use StreamDecoratorTrait;
/** @var string */
private $boundary;
/** @var StreamInterface */
private $stream;
/**
* @param array $elements Array of associative arrays, each containing a
* required "name" key mapping to the form field,
* name, a required "contents" key mapping to a
* StreamInterface/resource/string, an optional
* "headers" associative array of custom headers,
* and an optional "filename" key mapping to a
* string to send as the filename in the part.
* @param string $boundary You can optionally provide a specific boundary
*
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], ?string $boundary = null) {
$this->boundary = $boundary ?: bin2hex(random_bytes(20));
$this->stream = $this->createStream($elements);
}
public function getBoundary() : string {
return $this->boundary;
}
public function isWritable() : bool {
return false;
}
/**
* Get the headers needed before transferring the content of a POST file
*
* @param string[] $headers
*/
private function getHeaders(array $headers) : string {
$str = '';
foreach ($headers as $key => $value) {
$str .= "{$key}: {$value}\r\n";
}
return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
}
/**
* Create the aggregate stream that will be used to upload the POST data
*/
protected function createStream(array $elements = []) : StreamInterface {
$stream = new AppendStream();
foreach ($elements as $element) {
if (!is_array($element)) {
throw new \UnexpectedValueException('An array is expected');
}
$this->addElement($stream, $element);
}
// Add the trailing boundary with CRLF
$stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));
return $stream;
}
private function addElement(AppendStream $stream, array $element) : void {
foreach ([
'contents',
'name',
] as $key) {
if (!array_key_exists($key, $element)) {
throw new \InvalidArgumentException("A '{$key}' key is required");
}
}
$element['contents'] = Utils::streamFor($element['contents']);
if (empty($element['filename'])) {
$uri = $element['contents']->getMetadata('uri');
if ($uri && \is_string($uri) && \substr($uri, 0, 6) !== 'php://' && \substr($uri, 0, 7) !== 'data://') {
$element['filename'] = $uri;
}
}
[
$body,
$headers,
] = $this->createElement($element['name'], $element['contents'], $element['filename'] ?? null, $element['headers'] ?? []);
$stream->addStream(Utils::streamFor($this->getHeaders($headers)));
$stream->addStream($body);
$stream->addStream(Utils::streamFor("\r\n"));
}
/**
* @param string[] $headers
*
* @return array{0: StreamInterface, 1: string[]}
*/
private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers) : array {
// Set a default content-disposition header if one was no provided
$disposition = self::getHeader($headers, 'content-disposition');
if (!$disposition) {
$headers['Content-Disposition'] = $filename === '0' || $filename ? sprintf('form-data; name="%s"; filename="%s"', $name, basename($filename)) : "form-data; name=\"{$name}\"";
}
// Set a default content-length header if one was no provided
$length = self::getHeader($headers, 'content-length');
if (!$length) {
if ($length = $stream->getSize()) {
$headers['Content-Length'] = (string) $length;
}
}
// Set a default Content-Type if one was not supplied
$type = self::getHeader($headers, 'content-type');
if (!$type && ($filename === '0' || $filename)) {
$headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream';
}
return [
$stream,
$headers,
];
}
/**
* @param string[] $headers
*/
private static function getHeader(array $headers, string $key) : ?string {
$lowercaseHeader = strtolower($key);
foreach ($headers as $k => $v) {
if (strtolower((string) $k) === $lowercaseHeader) {
return $v;
}
}
return null;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
MultipartStream::$boundary | private | property | @var string | ||
MultipartStream::$stream | private | property | @var StreamInterface | ||
MultipartStream::addElement | private | function | |||
MultipartStream::createElement | private | function | |||
MultipartStream::createStream | protected | function | Create the aggregate stream that will be used to upload the POST data | Overrides StreamDecoratorTrait::createStream | |
MultipartStream::getBoundary | public | function | |||
MultipartStream::getHeader | private static | function | |||
MultipartStream::getHeaders | private | function | Get the headers needed before transferring the content of a POST file | ||
MultipartStream::isWritable | public | function | Returns whether or not the stream is writable. | Overrides StreamDecoratorTrait::isWritable | |
MultipartStream::__construct | public | function | Overrides StreamDecoratorTrait::__construct | ||
StreamDecoratorTrait::close | public | function | 1 | ||
StreamDecoratorTrait::detach | public | function | |||
StreamDecoratorTrait::eof | public | function | 2 | ||
StreamDecoratorTrait::getContents | public | function | |||
StreamDecoratorTrait::getMetadata | public | function | |||
StreamDecoratorTrait::getSize | public | function | 2 | ||
StreamDecoratorTrait::isReadable | public | function | |||
StreamDecoratorTrait::isSeekable | public | function | 1 | ||
StreamDecoratorTrait::read | public | function | 2 | ||
StreamDecoratorTrait::rewind | public | function | 1 | ||
StreamDecoratorTrait::seek | public | function | 3 | ||
StreamDecoratorTrait::tell | public | function | 1 | ||
StreamDecoratorTrait::write | public | function | 2 | ||
StreamDecoratorTrait::__call | public | function | Allow decorators to implement custom methods | ||
StreamDecoratorTrait::__get | public | function | Magic method used to create a new stream if streams are not added in the constructor of a decorator (e.g., LazyOpenStream). |
||
StreamDecoratorTrait::__toString | public | function |