summaryrefslogtreecommitdiff
path: root/vendor/symfony/mime/Part
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/mime/Part')
-rw-r--r--vendor/symfony/mime/Part/AbstractMultipartPart.php87
-rw-r--r--vendor/symfony/mime/Part/AbstractPart.php62
-rw-r--r--vendor/symfony/mime/Part/DataPart.php150
-rw-r--r--vendor/symfony/mime/Part/MessagePart.php64
-rw-r--r--vendor/symfony/mime/Part/Multipart/AlternativePart.php27
-rw-r--r--vendor/symfony/mime/Part/Multipart/DigestPart.php33
-rw-r--r--vendor/symfony/mime/Part/Multipart/FormDataPart.php96
-rw-r--r--vendor/symfony/mime/Part/Multipart/MixedPart.php27
-rw-r--r--vendor/symfony/mime/Part/Multipart/RelatedPart.php57
-rw-r--r--vendor/symfony/mime/Part/TextPart.php190
10 files changed, 793 insertions, 0 deletions
diff --git a/vendor/symfony/mime/Part/AbstractMultipartPart.php b/vendor/symfony/mime/Part/AbstractMultipartPart.php
new file mode 100644
index 0000000000..34a94d25bc
--- /dev/null
+++ b/vendor/symfony/mime/Part/AbstractMultipartPart.php
@@ -0,0 +1,87 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part;
+
+use Symfony\Component\Mime\Header\Headers;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+abstract class AbstractMultipartPart extends AbstractPart
+{
+ private $boundary;
+ private $parts = [];
+
+ public function __construct(AbstractPart ...$parts)
+ {
+ parent::__construct();
+
+ foreach ($parts as $part) {
+ $this->parts[] = $part;
+ }
+ }
+
+ /**
+ * @return AbstractPart[]
+ */
+ public function getParts(): array
+ {
+ return $this->parts;
+ }
+
+ public function getMediaType(): string
+ {
+ return 'multipart';
+ }
+
+ public function getPreparedHeaders(): Headers
+ {
+ $headers = parent::getPreparedHeaders();
+ $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary());
+
+ return $headers;
+ }
+
+ public function bodyToString(): string
+ {
+ $parts = $this->getParts();
+ $string = '';
+ foreach ($parts as $part) {
+ $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n";
+ }
+ $string .= '--'.$this->getBoundary()."--\r\n";
+
+ return $string;
+ }
+
+ public function bodyToIterable(): iterable
+ {
+ $parts = $this->getParts();
+ foreach ($parts as $part) {
+ yield '--'.$this->getBoundary()."\r\n";
+ yield from $part->toIterable();
+ yield "\r\n";
+ }
+ yield '--'.$this->getBoundary()."--\r\n";
+ }
+
+ private function getBoundary(): string
+ {
+ if (null === $this->boundary) {
+ $this->boundary = '_=_symfony_'.time().'_'.bin2hex(random_bytes(16)).'_=_';
+ }
+
+ return $this->boundary;
+ }
+}
diff --git a/vendor/symfony/mime/Part/AbstractPart.php b/vendor/symfony/mime/Part/AbstractPart.php
new file mode 100644
index 0000000000..29eaa1ebfd
--- /dev/null
+++ b/vendor/symfony/mime/Part/AbstractPart.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part;
+
+use Symfony\Component\Mime\Header\Headers;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+abstract class AbstractPart
+{
+ private $headers;
+
+ public function __construct()
+ {
+ $this->headers = new Headers();
+ }
+
+ public function getHeaders(): Headers
+ {
+ return $this->headers;
+ }
+
+ public function getPreparedHeaders(): Headers
+ {
+ $headers = clone $this->headers;
+ $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype());
+
+ return $headers;
+ }
+
+ public function toString(): string
+ {
+ return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString();
+ }
+
+ public function toIterable(): iterable
+ {
+ yield $this->getPreparedHeaders()->toString();
+ yield "\r\n";
+ yield from $this->bodyToIterable();
+ }
+
+ abstract public function bodyToString(): string;
+
+ abstract public function bodyToIterable(): iterable;
+
+ abstract public function getMediaType(): string;
+
+ abstract public function getMediaSubtype(): string;
+}
diff --git a/vendor/symfony/mime/Part/DataPart.php b/vendor/symfony/mime/Part/DataPart.php
new file mode 100644
index 0000000000..1cfb1e69b0
--- /dev/null
+++ b/vendor/symfony/mime/Part/DataPart.php
@@ -0,0 +1,150 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part;
+
+use Symfony\Component\Mime\Exception\InvalidArgumentException;
+use Symfony\Component\Mime\Header\Headers;
+use Symfony\Component\Mime\MimeTypes;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+class DataPart extends TextPart
+{
+ private static $mimeTypes;
+
+ private $filename;
+ private $mediaType;
+ private $cid;
+ private $handle;
+
+ /**
+ * @param resource|string $body
+ */
+ public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null)
+ {
+ if (null === $contentType) {
+ $contentType = 'application/octet-stream';
+ }
+ list($this->mediaType, $subtype) = explode('/', $contentType);
+
+ parent::__construct($body, null, $subtype, $encoding);
+
+ $this->filename = $filename;
+ $this->setName($filename);
+ $this->setDisposition('attachment');
+ }
+
+ public static function fromPath(string $path, string $name = null, string $contentType = null): self
+ {
+ // FIXME: if file is not readable, exception?
+
+ if (null === $contentType) {
+ $ext = strtolower(substr($path, strrpos($path, '.') + 1));
+ if (null === self::$mimeTypes) {
+ self::$mimeTypes = new MimeTypes();
+ }
+ $contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream';
+ }
+
+ if (false === $handle = @fopen($path, 'r', false)) {
+ throw new InvalidArgumentException(sprintf('Unable to open path "%s"', $path));
+ }
+ $p = new self($handle, $name ?: basename($path), $contentType);
+ $p->handle = $handle;
+
+ return $p;
+ }
+
+ /**
+ * @return $this
+ */
+ public function asInline()
+ {
+ return $this->setDisposition('inline');
+ }
+
+ public function getContentId(): string
+ {
+ return $this->cid ?: $this->cid = $this->generateContentId();
+ }
+
+ public function hasContentId(): bool
+ {
+ return null !== $this->cid;
+ }
+
+ public function getMediaType(): string
+ {
+ return $this->mediaType;
+ }
+
+ public function getPreparedHeaders(): Headers
+ {
+ $headers = parent::getPreparedHeaders();
+
+ if (null !== $this->cid) {
+ $headers->setHeaderBody('Id', 'Content-ID', $this->cid);
+ }
+
+ if (null !== $this->filename) {
+ $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename);
+ }
+
+ return $headers;
+ }
+
+ private function generateContentId(): string
+ {
+ return bin2hex(random_bytes(16)).'@symfony';
+ }
+
+ public function __destruct()
+ {
+ if (null !== $this->handle && \is_resource($this->handle)) {
+ fclose($this->handle);
+ }
+ }
+
+ public function __sleep()
+ {
+ // converts the body to a string
+ parent::__sleep();
+
+ $this->_parent = [];
+ foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) {
+ $r = new \ReflectionProperty(TextPart::class, $name);
+ $r->setAccessible(true);
+ $this->_parent[$name] = $r->getValue($this);
+ }
+ $this->_headers = $this->getHeaders();
+
+ return ['_headers', '_parent', 'filename', 'mediaType'];
+ }
+
+ public function __wakeup()
+ {
+ $r = new \ReflectionProperty(AbstractPart::class, 'headers');
+ $r->setAccessible(true);
+ $r->setValue($this, $this->_headers);
+ unset($this->_headers);
+
+ foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) {
+ $r = new \ReflectionProperty(TextPart::class, $name);
+ $r->setAccessible(true);
+ $r->setValue($this, $this->_parent[$name]);
+ }
+ unset($this->_parent);
+ }
+}
diff --git a/vendor/symfony/mime/Part/MessagePart.php b/vendor/symfony/mime/Part/MessagePart.php
new file mode 100644
index 0000000000..64a5340422
--- /dev/null
+++ b/vendor/symfony/mime/Part/MessagePart.php
@@ -0,0 +1,64 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part;
+
+use Symfony\Component\Mime\Message;
+use Symfony\Component\Mime\RawMessage;
+
+/**
+ * @final
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+class MessagePart extends DataPart
+{
+ private $message;
+
+ public function __construct(RawMessage $message)
+ {
+ if ($message instanceof Message) {
+ $name = $message->getHeaders()->getHeaderBody('Subject').'.eml';
+ } else {
+ $name = 'email.eml';
+ }
+ parent::__construct('', $name);
+
+ $this->message = $message;
+ }
+
+ public function getMediaType(): string
+ {
+ return 'message';
+ }
+
+ public function getMediaSubtype(): string
+ {
+ return 'rfc822';
+ }
+
+ public function getBody(): string
+ {
+ return $this->message->toString();
+ }
+
+ public function bodyToString(): string
+ {
+ return $this->getBody();
+ }
+
+ public function bodyToIterable(): iterable
+ {
+ return $this->message->toIterable();
+ }
+}
diff --git a/vendor/symfony/mime/Part/Multipart/AlternativePart.php b/vendor/symfony/mime/Part/Multipart/AlternativePart.php
new file mode 100644
index 0000000000..ad316a490a
--- /dev/null
+++ b/vendor/symfony/mime/Part/Multipart/AlternativePart.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part\Multipart;
+
+use Symfony\Component\Mime\Part\AbstractMultipartPart;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class AlternativePart extends AbstractMultipartPart
+{
+ public function getMediaSubtype(): string
+ {
+ return 'alternative';
+ }
+}
diff --git a/vendor/symfony/mime/Part/Multipart/DigestPart.php b/vendor/symfony/mime/Part/Multipart/DigestPart.php
new file mode 100644
index 0000000000..6199e5b8db
--- /dev/null
+++ b/vendor/symfony/mime/Part/Multipart/DigestPart.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part\Multipart;
+
+use Symfony\Component\Mime\Part\AbstractMultipartPart;
+use Symfony\Component\Mime\Part\MessagePart;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class DigestPart extends AbstractMultipartPart
+{
+ public function __construct(MessagePart ...$parts)
+ {
+ parent::__construct(...$parts);
+ }
+
+ public function getMediaSubtype(): string
+ {
+ return 'digest';
+ }
+}
diff --git a/vendor/symfony/mime/Part/Multipart/FormDataPart.php b/vendor/symfony/mime/Part/Multipart/FormDataPart.php
new file mode 100644
index 0000000000..75d69a88a0
--- /dev/null
+++ b/vendor/symfony/mime/Part/Multipart/FormDataPart.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part\Multipart;
+
+use Symfony\Component\Mime\Exception\InvalidArgumentException;
+use Symfony\Component\Mime\Part\AbstractMultipartPart;
+use Symfony\Component\Mime\Part\DataPart;
+use Symfony\Component\Mime\Part\TextPart;
+
+/**
+ * Implements RFC 7578.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class FormDataPart extends AbstractMultipartPart
+{
+ private $fields = [];
+
+ /**
+ * @param (string|array|DataPart)[] $fields
+ */
+ public function __construct(array $fields = [])
+ {
+ parent::__construct();
+
+ foreach ($fields as $name => $value) {
+ if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) {
+ throw new InvalidArgumentException(sprintf('A form field value can only be a string, an array, or an instance of TextPart ("%s" given).', \is_object($value) ? \get_class($value) : \gettype($value)));
+ }
+
+ $this->fields[$name] = $value;
+ }
+ // HTTP does not support \r\n in header values
+ $this->getHeaders()->setMaxLineLength(PHP_INT_MAX);
+ }
+
+ public function getMediaSubtype(): string
+ {
+ return 'form-data';
+ }
+
+ public function getParts(): array
+ {
+ return $this->prepareFields($this->fields);
+ }
+
+ private function prepareFields(array $fields): array
+ {
+ $values = [];
+ array_walk_recursive($fields, function ($item, $key) use (&$values) {
+ if (!\is_array($item)) {
+ $values[] = $this->preparePart($key, $item);
+ }
+ });
+
+ return $values;
+ }
+
+ private function preparePart($name, $value): TextPart
+ {
+ if (\is_string($value)) {
+ return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit'));
+ }
+
+ return $this->configurePart($name, $value);
+ }
+
+ private function configurePart(string $name, TextPart $part): TextPart
+ {
+ static $r;
+
+ if (null === $r) {
+ $r = new \ReflectionProperty(TextPart::class, 'encoding');
+ $r->setAccessible(true);
+ }
+
+ $part->setDisposition('form-data');
+ $part->setName($name);
+ // HTTP does not support \r\n in header values
+ $part->getHeaders()->setMaxLineLength(PHP_INT_MAX);
+ $r->setValue($part, '8bit');
+
+ return $part;
+ }
+}
diff --git a/vendor/symfony/mime/Part/Multipart/MixedPart.php b/vendor/symfony/mime/Part/Multipart/MixedPart.php
new file mode 100644
index 0000000000..eaa869fbee
--- /dev/null
+++ b/vendor/symfony/mime/Part/Multipart/MixedPart.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part\Multipart;
+
+use Symfony\Component\Mime\Part\AbstractMultipartPart;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class MixedPart extends AbstractMultipartPart
+{
+ public function getMediaSubtype(): string
+ {
+ return 'mixed';
+ }
+}
diff --git a/vendor/symfony/mime/Part/Multipart/RelatedPart.php b/vendor/symfony/mime/Part/Multipart/RelatedPart.php
new file mode 100644
index 0000000000..2d5563073c
--- /dev/null
+++ b/vendor/symfony/mime/Part/Multipart/RelatedPart.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part\Multipart;
+
+use Symfony\Component\Mime\Part\AbstractMultipartPart;
+use Symfony\Component\Mime\Part\AbstractPart;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class RelatedPart extends AbstractMultipartPart
+{
+ private $mainPart;
+
+ public function __construct(AbstractPart $mainPart, AbstractPart $part, AbstractPart ...$parts)
+ {
+ $this->mainPart = $mainPart;
+ $this->prepareParts($part, ...$parts);
+
+ parent::__construct($part, ...$parts);
+ }
+
+ public function getParts(): array
+ {
+ return array_merge([$this->mainPart], parent::getParts());
+ }
+
+ public function getMediaSubtype(): string
+ {
+ return 'related';
+ }
+
+ private function generateContentId(): string
+ {
+ return bin2hex(random_bytes(16)).'@symfony';
+ }
+
+ private function prepareParts(AbstractPart ...$parts): void
+ {
+ foreach ($parts as $part) {
+ if (!$part->getHeaders()->has('Content-ID')) {
+ $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId());
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/mime/Part/TextPart.php b/vendor/symfony/mime/Part/TextPart.php
new file mode 100644
index 0000000000..6a04185315
--- /dev/null
+++ b/vendor/symfony/mime/Part/TextPart.php
@@ -0,0 +1,190 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Part;
+
+use Symfony\Component\Mime\Encoder\Base64ContentEncoder;
+use Symfony\Component\Mime\Encoder\ContentEncoderInterface;
+use Symfony\Component\Mime\Encoder\EightBitContentEncoder;
+use Symfony\Component\Mime\Encoder\QpContentEncoder;
+use Symfony\Component\Mime\Exception\InvalidArgumentException;
+use Symfony\Component\Mime\Header\Headers;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+class TextPart extends AbstractPart
+{
+ private static $encoders = [];
+
+ private $body;
+ private $charset;
+ private $subtype;
+ private $disposition;
+ private $name;
+ private $encoding;
+
+ /**
+ * @param resource|string $body
+ */
+ public function __construct($body, ?string $charset = 'utf-8', $subtype = 'plain', string $encoding = null)
+ {
+ parent::__construct();
+
+ if (!\is_string($body) && !\is_resource($body)) {
+ throw new \TypeError(sprintf('The body of "%s" must be a string or a resource (got "%s").', self::class, \is_object($body) ? \get_class($body) : \gettype($body)));
+ }
+
+ $this->body = $body;
+ $this->charset = $charset;
+ $this->subtype = $subtype;
+
+ if (null === $encoding) {
+ $this->encoding = $this->chooseEncoding();
+ } else {
+ if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) {
+ throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding));
+ }
+ $this->encoding = $encoding;
+ }
+ }
+
+ public function getMediaType(): string
+ {
+ return 'text';
+ }
+
+ public function getMediaSubtype(): string
+ {
+ return $this->subtype;
+ }
+
+ /**
+ * @param string $disposition one of attachment, inline, or form-data
+ *
+ * @return $this
+ */
+ public function setDisposition(string $disposition)
+ {
+ $this->disposition = $disposition;
+
+ return $this;
+ }
+
+ /**
+ * Sets the name of the file (used by FormDataPart).
+ *
+ * @return $this
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getBody(): string
+ {
+ if (!\is_resource($this->body)) {
+ return $this->body;
+ }
+
+ if (stream_get_meta_data($this->body)['seekable'] ?? false) {
+ rewind($this->body);
+ }
+
+ return stream_get_contents($this->body) ?: '';
+ }
+
+ public function bodyToString(): string
+ {
+ return $this->getEncoder()->encodeString($this->getBody(), $this->charset);
+ }
+
+ public function bodyToIterable(): iterable
+ {
+ if (\is_resource($this->body)) {
+ if (stream_get_meta_data($this->body)['seekable'] ?? false) {
+ rewind($this->body);
+ }
+ yield from $this->getEncoder()->encodeByteStream($this->body);
+ } else {
+ yield $this->getEncoder()->encodeString($this->body);
+ }
+ }
+
+ public function getPreparedHeaders(): Headers
+ {
+ $headers = parent::getPreparedHeaders();
+
+ $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype());
+ if ($this->charset) {
+ $headers->setHeaderParameter('Content-Type', 'charset', $this->charset);
+ }
+ if ($this->name) {
+ $headers->setHeaderParameter('Content-Type', 'name', $this->name);
+ }
+ $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding);
+
+ if (!$headers->has('Content-Disposition') && null !== $this->disposition) {
+ $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition);
+ if ($this->name) {
+ $headers->setHeaderParameter('Content-Disposition', 'name', $this->name);
+ }
+ }
+
+ return $headers;
+ }
+
+ private function getEncoder(): ContentEncoderInterface
+ {
+ if ('8bit' === $this->encoding) {
+ return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new EightBitContentEncoder());
+ }
+
+ if ('quoted-printable' === $this->encoding) {
+ return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new QpContentEncoder());
+ }
+
+ return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new Base64ContentEncoder());
+ }
+
+ private function chooseEncoding(): string
+ {
+ if (null === $this->charset) {
+ return 'base64';
+ }
+
+ return 'quoted-printable';
+ }
+
+ public function __sleep()
+ {
+ // convert resources to strings for serialization
+ if (\is_resource($this->body)) {
+ $this->body = $this->getBody();
+ }
+
+ $this->_headers = $this->getHeaders();
+
+ return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding'];
+ }
+
+ public function __wakeup()
+ {
+ $r = new \ReflectionProperty(AbstractPart::class, 'headers');
+ $r->setAccessible(true);
+ $r->setValue($this, $this->_headers);
+ unset($this->_headers);
+ }
+}