$parameters * @param array $dispositionParameters * @param list $language * @param list $parts */ public function __construct( private readonly string $partId, private readonly string $mimeType, private readonly array $parameters = [], private readonly ?string $contentId = null, private readonly ?string $description = null, private readonly ?string $encoding = null, private readonly ?int $size = null, private readonly ?string $disposition = null, private readonly array $dispositionParameters = [], private readonly array $language = [], private readonly ?string $location = null, private readonly ?string $content = null, private readonly array $parts = [], ) {} public function partId(): string { return $this->partId; } public function mimeType(): string { return $this->mimeType; } /** * @return array */ public function parameters(): array { return $this->parameters; } public function contentId(): ?string { return $this->contentId; } public function description(): ?string { return $this->description; } public function encoding(): ?string { return $this->encoding; } public function size(): ?int { return $this->size; } public function disposition(): ?string { return $this->disposition; } /** * @return array */ public function dispositionParameters(): array { return $this->dispositionParameters; } /** * @return list */ public function language(): array { return $this->language; } public function location(): ?string { return $this->location; } public function content(): ?string { return $this->content; } /** * @return list */ public function parts(): array { return $this->parts; } public function isMultipart(): bool { return str_starts_with($this->mimeType, 'multipart/'); } /** * @param array $sections */ public function withInjectedSections(array $sections): self { if ($this->parts !== []) { $parts = []; foreach ($this->parts as $part) { $parts[] = $part->withInjectedSections($sections); } return new self( $this->partId, $this->mimeType, $this->parameters, $this->contentId, $this->description, $this->encoding, $this->size, $this->disposition, $this->dispositionParameters, $this->language, $this->location, $this->content, $parts, ); } if (!str_starts_with($this->mimeType, 'text/')) { return $this; } if (!array_key_exists($this->partId, $sections)) { return $this; } return new self( $this->partId, $this->mimeType, $this->parameters, $this->contentId, $this->description, $this->encoding, $this->size, $this->disposition, $this->dispositionParameters, $this->language, $this->location, self::decodeContent($sections[$this->partId], $this->encoding, $this->parameters['charset'] ?? 'us-ascii'), [], ); } public function toArray(): array { $data = [ 'partId' => $this->partId, 'blobId' => $this->partId, 'cId' => $this->contentId, 'type' => $this->mimeType, 'charset' => $this->parameters['charset'] ?? null, 'name' => $this->parameters['name'] ?? $this->dispositionParameters['filename'] ?? null, 'encoding' => $this->encoding, 'size' => $this->size, 'disposition' => $this->disposition, 'language' => $this->language === [] ? null : implode(',', $this->language), 'location' => $this->location, 'content' => $this->content, ]; $children = []; foreach ($this->parts as $part) { $children[] = $part->toArray(); } $data['subParts'] = $children === [] ? null : $children; return array_filter($data, static fn (mixed $value): bool => $value !== null); } private static function decodeContent(string $content, ?string $encoding, string $charset): string { $decoded = match (strtolower($encoding ?? '7bit')) { 'quoted-printable' => quoted_printable_decode($content), 'base64' => base64_decode($content, true) ?: '', default => $content, }; if ($charset === '' || in_array(strtolower($charset), ['utf-8', 'utf8'], true)) { return mb_convert_encoding($decoded, 'UTF-8', 'UTF-8'); } try { $converted = mb_convert_encoding($decoded, 'UTF-8', $charset); if ($converted !== false) { return $converted; } } catch (\ValueError) { } $converted = @iconv($charset, 'UTF-8//TRANSLIT//IGNORE', $decoded); $decoded = $converted !== false ? $converted : $decoded; return mb_convert_encoding($decoded, 'UTF-8', 'UTF-8'); } }