filename = $filename; $this->content = $content; $this->contentType = $contentType; $this->encoding = $encoding; $this->isInlineAttachment = $isInlineAttachment; $this->cid = $cid; } /** * @param MailMessagePartInterface $part * * @throws InvalidArgumentException * * @return MailAttachmentData */ public static function fromMailMessagePart(MailMessagePartInterface $part): MailAttachmentData { $encodingHeader = $part->getHeader('content-transfer-encoding'); if ($encodingHeader === null) { // Assume this is no error (?) throw new InvalidArgumentException('missing header: "Content-Transfer-Encoding"'); $encoding = ''; } else { $encoding = $encodingHeader->getValue(); } $dispositionHeader = $part->getHeader('content-disposition'); if ($dispositionHeader === null) { throw new InvalidArgumentException('missing header: "Content-Disposition"'); } $disposition = $dispositionHeader->getValue(); /* Content-Disposition: inline Content-Disposition: attachment Content-Disposition: attachment; filename="filename.jpg" This is not correctly implemented -> only the first string is evaluated Content-Disposition: attachment; filename*0="filename_that_is_" Content-Disposition: attachment; filename*1="very_long.jpg" */ if (preg_match('/(.+);\s*filename(?:\*[0-9]){0,1}="([^"]+)".*$/m', $disposition, $matches)) { $isInline = strtolower($matches[1]) === 'inline'; $filename = $matches[2]; } else if ($disposition == 'attachment') { // Filename is given in Content-Type e.g. /* Content-Type: application/pdf; name="Filename.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment */ $contenttypeHeader = $part->getHeader('content-type'); if ($contenttypeHeader === null) { throw new InvalidArgumentException('missing header: "Content-Type"'); } $contenttype = $contenttypeHeader->getValue(); if (preg_match('/(.+);\s*name(?:\*[0-9]){0,1}="([^"]+)".*$/m', $contenttype, $matches)) { $isInline = strtolower($matches[1]) === 'inline'; $filename = $matches[2]; } else { throw new InvalidArgumentException( sprintf('missing filename in header value "Content-Type" = "%s"', $contenttype) ); } } else if ($disposition == 'inline') { $isInline = true; $filename = ""; // This is questionable } else if (strpos($disposition,'attachment;\n') == 0) { // No filename, check for content type message/rfc822 $contenttypeHeader = $part->getHeader('content-type'); if ($contenttypeHeader === null) { throw new InvalidArgumentException('missing header: "Content-Type"'); } $contenttype = $contenttypeHeader->getValue(); if ($contenttype == 'message/rfc822') { $isInline = false; $filename = 'ForwardedMessage.eml'; } else { throw new InvalidArgumentException( sprintf('unexpected header value "Content-Disposition" = "%s"', $disposition) ); } } else { throw new InvalidArgumentException( sprintf('unexpected header value "Content-Disposition" = "%s", not message/rfc822', $disposition) ); } // Thunderbird UTF URL-Format $UTF_pos = strpos($filename,'UTF-8\'\''); if ($UTF_pos !== false) { $wasUTF = "JA"; $filename = substr($filename,$UTF_pos); $filename = rawurldecode($filename); } $cid = null; $contentIdHeader = $part->getHeader('content-id'); if ($contentIdHeader !== null) { $cid = $contentIdHeader->getValue(); if (preg_match('/[<]?([^<>]+)[>]?$/', $cid, $cidMatches)) { $cid = $cidMatches[1]; } } return new self( $filename, $part->getContent(), $part->getContentType(), $encoding, $isInline, $cid ); } /** * @return string */ public function getFileName(): string { return $this->filename; } /** * @return string */ public function getContent(): string { switch ($this->encoding) { case 'base64': return base64_decode($this->content); default: return $this->content; } } /** * @return string */ public function getContentType(): string { return $this->contentType; } /** * @return string */ public function getTransferEncoding(): string { return $this->encoding; } /** * @return bool */ public function isInlineAttachment(): bool { return $this->isInlineAttachment; } /** * @return string|null */ public function getCid(): ?string { return $this->cid; } }