3
namespace GuzzleHttp\Post;
5
use GuzzleHttp\Stream\AppendStream;
6
use GuzzleHttp\Stream\Stream;
7
use GuzzleHttp\Stream\StreamDecoratorTrait;
8
use GuzzleHttp\Stream\StreamInterface;
11
* Stream that when read returns bytes for a streaming multipart/form-data body
13
class MultipartBody implements StreamInterface
15
use StreamDecoratorTrait;
20
* @param array $fields Associative array of field names to values where
21
* each value is a string or array of strings.
22
* @param array $files Associative array of PostFileInterface objects
23
* @param string $boundary You can optionally provide a specific boundary
24
* @throws \InvalidArgumentException
26
public function __construct(
31
$this->boundary = $boundary ?: uniqid();
32
$this->stream = $this->createStream($fields, $files);
40
public function getBoundary()
42
return $this->boundary;
45
public function isWritable()
51
* Get the string needed to transfer a POST field
53
private function getFieldString($name, $value)
56
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
64
* Get the headers needed before transferring the content of a POST file
66
private function getFileHeaders(PostFileInterface $file)
69
foreach ($file->getHeaders() as $key => $value) {
70
$headers .= "{$key}: {$value}\r\n";
73
return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
77
* Create the aggregate stream that will be used to upload the POST data
79
private function createStream(array $fields, array $files)
81
$stream = new AppendStream();
83
foreach ($fields as $name => $fieldValues) {
84
foreach ((array) $fieldValues as $value) {
86
Stream::factory($this->getFieldString($name, $value))
91
foreach ($files as $file) {
93
if (!$file instanceof PostFileInterface) {
94
throw new \InvalidArgumentException('All POST fields must '
95
. 'implement PostFieldInterface');
99
Stream::factory($this->getFileHeaders($file))
101
$stream->addStream($file->getContent());
102
$stream->addStream(Stream::factory("\r\n"));
105
// Add the trailing boundary
106
$stream->addStream(Stream::factory("--{$this->boundary}--"));