12     use StreamDecoratorTrait;
 
   28     public function __construct(array $elements = [], $boundary = 
null)
 
   30         $this->boundary = $boundary ?: sha1(uniqid(
'', 
true));
 
   41         return $this->boundary;
 
   52     private function getHeaders(array $headers)
 
   55         foreach ($headers as $key => $value) {
 
   56             $str .= 
"{$key}: {$value}\r\n";
 
   59         return "--{$this->boundary}\r\n" . trim($str) . 
"\r\n\r\n";
 
   69         foreach ($elements as $element) {
 
   70             $this->addElement($stream, $element);
 
   74         $stream->addStream(
stream_for(
"--{$this->boundary}--\r\n"));
 
   79     private function addElement(
AppendStream $stream, array $element)
 
   81         foreach ([
'contents', 
'name'] as $key) {
 
   82             if (!array_key_exists($key, $element)) {
 
   83                 throw new \InvalidArgumentException(
"A '{$key}' key is required");
 
   87         $element[
'contents'] = 
stream_for($element[
'contents']);
 
   89         if (empty($element[
'filename'])) {
 
   90             $uri = $element[
'contents']->getMetadata(
'uri');
 
   91             if (substr($uri, 0, 6) !== 
'php://') {
 
   92                 $element[
'filename'] = $uri;
 
   96         list($body, $headers) = $this->createElement(
 
   99             isset($element[
'filename']) ? $element[
'filename'] : 
null,
 
  100             isset($element[
'headers']) ? $element[
'headers'] : []
 
  103         $stream->addStream(
stream_for($this->getHeaders($headers)));
 
  104         $stream->addStream($body);
 
  111     private function createElement($name, StreamInterface $stream, $filename, array $headers)
 
  114         $disposition = $this->getHeader($headers, 
'content-disposition');
 
  116             $headers[
'Content-Disposition'] = ($filename === 
'0' || $filename)
 
  117                 ? sprintf(
'form-data; name="%s"; filename="%s"',
 
  120                 : 
"form-data; name=\"{$name}\"";
 
  124         $length = $this->getHeader($headers, 
'content-length');
 
  126             if ($length = $stream->getSize()) {
 
  127                 $headers[
'Content-Length'] = (string) $length;
 
  132         $type = $this->getHeader($headers, 
'content-type');
 
  133         if (!$type && ($filename === 
'0' || $filename)) {
 
  135                 $headers[
'Content-Type'] = $type;
 
  139         return [$stream, $headers];
 
  142     private function getHeader(array $headers, $key)
 
  144         $lowercaseHeader = strtolower($key);
 
  145         foreach ($headers as $k => $v) {
 
  146             if (strtolower($k) === $lowercaseHeader) {