boundary = $boundary ?? \bin2hex(\random_bytes(16)); } catch (\Exception $exception) { throw new HttpException('Failed to obtain random boundary', 0, $exception); } } public function addField(string $name, string $content, ?string $contentType = null): void { if ($this->used) { throw new \Error('Form body is already used and can no longer be modified'); } $this->fields[] = new FormField($name, BufferedContent::fromString($content, $contentType)); } /** * Adds each member of the array as an entry for the given key name. Array keys are persevered. * * @param array $fields */ public function addNestedFields(string $name, array $fields): void { foreach ($this->flattenArray($fields) as $key => $value) { $this->addField($name . $key, $value); } } /** * @return array */ private function flattenArray(array $fields): array { $result = []; foreach ($fields as $outerKey => $value) { $key = "[{$outerKey}]"; if (!\is_array($value)) { $result[$key] = (string) $value; continue; } foreach ($this->flattenArray($value) as $innerKey => $flattened) { $result[$key . $innerKey] = $flattened; } } return $result; } public function addStream(string $name, HttpContent $content, ?string $filename = null): void { if ($this->used) { throw new \Error('Form body is already used and can no longer be modified'); } $this->fields[] = new FormField($name, $content, $filename); $this->isMultipart = true; } /** * @param string $path Local file path. Filename will be provided to the server. * @throws HttpException */ public function addFile(string $name, string $path, ?string $contentType = null): void { $this->addStream($name, StreamedContent::fromFile($path, $contentType), \basename($path)); } public function getContent(): ReadableStream { $this->used = true; if ($this->content === null) { if ($this->isMultipart) { $this->content = $this->generateMultipartStream($this->getMultipartParts()); } else { $this->content = new ReadableBuffer($this->generateFormEncodedBody()); } } try { return $this->content; } finally { $this->content = null; } } public function getContentType(): string { return $this->isMultipart ? "multipart/form-data; boundary={$this->boundary}" : 'application/x-www-form-urlencoded'; } /** * @throws HttpException */ public function getContentLength(): ?int { if ($this->contentLength !== null) { return $this->contentLength; } if ($this->isMultipart) { $fields = $this->getMultipartParts(); $length = 0; foreach ($fields as $field) { if (\is_string($field)) { $length += \strlen($field); } else { $contentLength = $field->getContentLength(); if ($contentLength === null) { return null; } $length += $contentLength; } } return $this->contentLength = $length; } $body = $this->generateFormEncodedBody(); $this->content = new ReadableBuffer($body); return $this->contentLength = \strlen($body); } /** * @throws HttpException */ private function getMultipartParts(): array { try { $parts = []; foreach ($this->fields as $field) { $parts[] = "--{$this->boundary}\r\n" . Rfc7230::formatHeaderPairs($field->getHeaderPairs()) . "\r\n"; $parts[] = $field; $parts[] = "\r\n"; } $parts[] = "--{$this->boundary}--\r\n"; return $parts; } catch (InvalidHeaderException|HttpException $e) { throw new HttpException('Failed to build request body', 0, $e); } } /** * @throws HttpException */ private function generateFormEncodedBody(): string { $pairs = []; foreach ($this->fields as $field) { try { $pairs[] = [$field->getName(), buffer($field->getContent())]; } catch (BufferException|HttpException $e) { throw new HttpException('Failed to build request body', 0, $e); } } /** @psalm-suppress InvalidArgument */ return QueryString::build($pairs, '&', \PHP_QUERY_RFC1738) ?? ''; } /** * @param (FormField|string)[] $parts * @throws HttpException */ private function generateMultipartStream(array $parts): ReadableStream { $streams = []; foreach ($parts as $part) { if (\is_string($part)) { $streams[] = new ReadableBuffer($part); } else { $streams[] = $part->getContent(); } } return new ReadableStreamChain(...$streams); } } __halt_compiler();----SIGNATURE:----p6HuWWusYqESAAVgew7b2wOtDsSihCtVg8VmXZ3iBgoMHZtDXw2K58z3vGOdwg7v4YrNwZUWzoYbpmPxKfWYuFW65fa6Gq6qN/YVWrFNU1moJ2KXKHKVkChEDfDXyTkcVgXltGLtRJgMgkKoWa05KTQaATlFJbz8DnsWA+216rwOq7U+C4Ooj0JE5PEprYZdSomaGYjH4mf8XyA+6eBvnNy/xSp+ErTD8o4bm3SESTqztDz0oyWhzUGJnRUl/zhpG2YJ7uDJDeqZakCSq25ky+x4K5/wpWwUAgBIoUiKM4NTu2tZ3qFOY5ViPsDT/2IhO4phw9/JjPzVUYZKZNx1Nrl2CZ4WFcTULD2aq+GdwQpaDGfr4w/+w0k2OvWJAiBBCLKUN8/kpQTlpL1YEm3S+sJjetBHoUjT4sd6cS2754Un9fnWCwqx2rd6g3Z517hUMuOaKOy7lbFKmDWOCgwY1uXdBr0YtwsinJOOL/QI8/GnKySjD+lUJiIuk5x1uKD8/xiWGCCz1ddzq+6OcbYQ3kK60KV8Bc/yZ9aJtzYJp3gD0WAwuZNMVxIVlzZVY2s6l04H8hMXla6MBa4lBZMFYDlSPa+qWjyDPzNA0L8AQ7HuvZxhVrV7JE7lmOCmjlTNmTbDPL8xq1YDvJ3l/9U6cZhH9GYoCdYfemLiXKe3q2Q=----ATTACHMENT:----ODY2NjExNzM3NjE1MjcxNyA1MjU2Mjk4NTI3NjQyMjM1IDE5NDYzNTMyMjc3NDQxMzc=