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:----EVGDTQamZpuMUFSuzeF+tmFd7q9RKMQ3nKBOorvJiSA+uQXTV8t1oPTY0WenY3lHnSM+LUW1CDCsINQntFzlGhx3AaJDvqeqMWwP4dAC/3HYRBuoYM4g0GmctXRFt4kyicgRGII4lXzY8W9CJyq6jvWpSn2OCOcSyk4T60oD2RaRlxC7Wpt7h+CwYxuUsc9O3mcyQLJVq8R9X3agS8cHUktCM4OrBQ9Wo4hc8hRCebZam+KRxMiiUYWGUJnmBER/cdCsAM5WMctiAxUepYs6YLL9zIvQMwpotQ11vcWZydIjPRYiRbCRKuzBa8wTV1h6xvyf2H4hAacKrOLigKzg5AV2/i61/pAn70vDYNFc9L/WINtzrgR1P5AA3kJ89rb6wKg1rdYLJQNnFoVyLHvPDVhOwz1tRcD/nRImtHidvfQMljAJVyUUym7cCJ2g6q2dfwCEWuLcVDpyMDDhO8PCdtTKA3bKjsfe2/xW38/3gdNBQxFAZJ4wNCc7R3HQugdiH93+pkvQDwHUuxCQ4g0e95fGuHP+hujwYJEHXUaZgN+1YIY4vPkvfZzNgQI7TuzWVh38LSFd3uSu4ca7rgKAxyQmYO8luCfG1A0Y5Q0xAFEhxtHGsbEt4YM77rNWqVrQ4OMJ7WzVjYjvNVU3j2ijLdI4C3Smc8IwBbfhY34c2LY=----ATTACHMENT:----MTQwMTE3MTk2MzA5NzA1MSA4MzA0MzQyMDUwNTM1ODgxIDI1NzQwOTQwMTU1MTU1MDI=