mirror of
https://github.com/itflow-org/itflow
synced 2026-03-14 01:34:51 +00:00
Add new optional beta email parser thats based on ImapEngine instead of Webklex
This commit is contained in:
42
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMessagePartFactory.php
vendored
Normal file
42
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMessagePartFactory.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
|
||||
/**
|
||||
* Abstract factory for subclasses of IMessagePart.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class IMessagePartFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
protected PartStreamContainerFactory $partStreamContainerFactory;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
PartStreamContainerFactory $partStreamContainerFactory
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->partStreamContainerFactory = $partStreamContainerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new IMessagePart object and returns it
|
||||
*/
|
||||
abstract public function newInstance(?IMimePart $parent = null) : IMessagePart;
|
||||
}
|
||||
55
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMimePartFactory.php
vendored
Normal file
55
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMimePartFactory.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\MimePart;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
|
||||
/**
|
||||
* Responsible for creating IMimePart instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IMimePartFactory extends IMessagePartFactory
|
||||
{
|
||||
protected PartHeaderContainerFactory $partHeaderContainerFactory;
|
||||
|
||||
protected PartChildrenContainerFactory $partChildrenContainerFactory;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
PartStreamContainerFactory $partStreamContainerFactory,
|
||||
PartHeaderContainerFactory $partHeaderContainerFactory,
|
||||
PartChildrenContainerFactory $partChildrenContainerFactory
|
||||
) {
|
||||
parent::__construct($logger, $streamFactory, $partStreamContainerFactory);
|
||||
$this->partHeaderContainerFactory = $partHeaderContainerFactory;
|
||||
$this->partChildrenContainerFactory = $partChildrenContainerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new IMimePart object and returns it
|
||||
*/
|
||||
public function newInstance(?IMimePart $parent = null) : IMimePart
|
||||
{
|
||||
$streamContainer = $this->partStreamContainerFactory->newInstance();
|
||||
$headerContainer = $this->partHeaderContainerFactory->newInstance();
|
||||
$part = new MimePart(
|
||||
$parent,
|
||||
$this->logger,
|
||||
$streamContainer,
|
||||
$headerContainer,
|
||||
$this->partChildrenContainerFactory->newInstance()
|
||||
);
|
||||
$streamContainer->setStream($this->streamFactory->newMessagePartStream($part));
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IUUEncodedPartFactory.php
vendored
Normal file
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IUUEncodedPartFactory.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\IUUEncodedPart;
|
||||
use ZBateson\MailMimeParser\Message\UUEncodedPart;
|
||||
|
||||
/**
|
||||
* Responsible for creating UUEncodedPart instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IUUEncodedPartFactory extends IMessagePartFactory
|
||||
{
|
||||
/**
|
||||
* Constructs a new UUEncodedPart object and returns it
|
||||
*/
|
||||
public function newInstance(?IMimePart $parent = null) : IUUEncodedPart
|
||||
{
|
||||
$streamContainer = $this->partStreamContainerFactory->newInstance();
|
||||
$part = new UUEncodedPart(
|
||||
null,
|
||||
null,
|
||||
$parent,
|
||||
$this->logger,
|
||||
$streamContainer
|
||||
);
|
||||
$streamContainer->setStream($this->streamFactory->newMessagePartStream($part));
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
23
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartChildrenContainerFactory.php
vendored
Normal file
23
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartChildrenContainerFactory.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\PartChildrenContainer;
|
||||
|
||||
/**
|
||||
* Creates PartChildrenContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartChildrenContainerFactory
|
||||
{
|
||||
public function newInstance() : PartChildrenContainer
|
||||
{
|
||||
return new PartChildrenContainer();
|
||||
}
|
||||
}
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartHeaderContainerFactory.php
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartHeaderContainerFactory.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\HeaderFactory;
|
||||
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
|
||||
|
||||
/**
|
||||
* Creates PartHeaderContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartHeaderContainerFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var HeaderFactory the HeaderFactory passed to HeaderContainer instances.
|
||||
*/
|
||||
protected HeaderFactory $headerFactory;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, HeaderFactory $headerFactory)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->headerFactory = $headerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a PartHeaderContainer.
|
||||
*/
|
||||
public function newInstance(?PartHeaderContainer $from = null) : PartHeaderContainer
|
||||
{
|
||||
return new PartHeaderContainer($this->logger, $this->headerFactory, $from);
|
||||
}
|
||||
}
|
||||
51
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartStreamContainerFactory.php
vendored
Normal file
51
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartStreamContainerFactory.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\PartStreamContainer;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Creates PartStreamContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartStreamContainerFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
protected MbWrapper $mbWrapper;
|
||||
|
||||
protected bool $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
MbWrapper $mbWrapper,
|
||||
bool $throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->mbWrapper = $mbWrapper;
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets = $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
}
|
||||
|
||||
public function newInstance() : PartStreamContainer
|
||||
{
|
||||
return new PartStreamContainer(
|
||||
$this->logger,
|
||||
$this->streamFactory,
|
||||
$this->mbWrapper,
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
);
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/AbstractHelper.php
vendored
Normal file
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/AbstractHelper.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
|
||||
/**
|
||||
* Base class for message helpers.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var IMimePartFactory to create parts for attachments/content
|
||||
*/
|
||||
protected IMimePartFactory $mimePartFactory;
|
||||
|
||||
/**
|
||||
* @var IUUEncodedPartFactory to create parts for attachments
|
||||
*/
|
||||
protected IUUEncodedPartFactory $uuEncodedPartFactory;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory
|
||||
) {
|
||||
$this->mimePartFactory = $mimePartFactory;
|
||||
$this->uuEncodedPartFactory = $uuEncodedPartFactory;
|
||||
}
|
||||
}
|
||||
161
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/GenericHelper.php
vendored
Normal file
161
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/GenericHelper.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
|
||||
/**
|
||||
* Provides common Message helper routines for Message manipulation.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var string[] non mime content fields that are not related to the content
|
||||
* of a part.
|
||||
*/
|
||||
private static array $nonMimeContentFields = ['contentreturn', 'contentidentifier'];
|
||||
|
||||
/**
|
||||
* Returns true if the passed header's name is a Content-* header other than
|
||||
* one defined in the static $nonMimeContentFields
|
||||
*
|
||||
*/
|
||||
private function isMimeContentField(IHeader $header, array $exceptions = []) : bool
|
||||
{
|
||||
return (\stripos($header->getName(), 'Content') === 0
|
||||
&& !\in_array(\strtolower(\str_replace('-', '', $header->getName())), \array_merge(self::$nonMimeContentFields, $exceptions)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the passed $header from $from, to $to or sets the header to
|
||||
* $default if it doesn't exist in $from.
|
||||
*
|
||||
* @param string $header
|
||||
* @param string $default
|
||||
*/
|
||||
public function copyHeader(IMimePart $from, IMimePart $to, $header, $default = null) : static
|
||||
{
|
||||
$fromHeader = $from->getHeader($header);
|
||||
$set = ($fromHeader !== null) ? $fromHeader->getRawValue() : $default;
|
||||
if ($set !== null) {
|
||||
$to->setRawHeader($header, $set);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes Content-* headers from the passed part, then detaches its content
|
||||
* stream.
|
||||
*
|
||||
* An exception is made for the obsolete Content-Return header, which isn't
|
||||
* isn't a MIME content field and so isn't removed.
|
||||
*/
|
||||
public function removeContentHeadersAndContent(IMimePart $part) : static
|
||||
{
|
||||
foreach ($part->getAllHeaders() as $header) {
|
||||
if ($this->isMimeContentField($header)) {
|
||||
$part->removeHeader($header->getName());
|
||||
}
|
||||
}
|
||||
$part->detachContentStream();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies Content-* headers from the $from header into the $to header. If
|
||||
* the Content-Type header isn't defined in $from, defaults to text/plain
|
||||
* with utf-8 and quoted-printable as its Content-Transfer-Encoding.
|
||||
*
|
||||
* An exception is made for the obsolete Content-Return header, which isn't
|
||||
* isn't a MIME content field and so isn't copied.
|
||||
*
|
||||
* @param bool $move
|
||||
*/
|
||||
public function copyContentHeadersAndContent(IMimePart $from, IMimePart $to, $move = false) : static
|
||||
{
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TYPE, 'text/plain; charset=utf-8');
|
||||
if ($from->getHeader(HeaderConsts::CONTENT_TYPE) === null) {
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
|
||||
} else {
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TRANSFER_ENCODING);
|
||||
}
|
||||
foreach ($from->getAllHeaders() as $header) {
|
||||
if ($this->isMimeContentField($header, ['contenttype', 'contenttransferencoding'])) {
|
||||
$this->copyHeader($from, $to, $header->getName());
|
||||
}
|
||||
}
|
||||
if ($from->hasContent()) {
|
||||
$to->attachContentStream($from->getContentStream(), MailMimeParser::DEFAULT_CHARSET);
|
||||
}
|
||||
if ($move) {
|
||||
$this->removeContentHeadersAndContent($from);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new content part from the passed part, allowing the part to be
|
||||
* used for something else (e.g. changing a non-mime message to a multipart
|
||||
* mime message).
|
||||
*
|
||||
* @return IMimePart the newly-created IMimePart
|
||||
*/
|
||||
public function createNewContentPartFrom(IMimePart $part) : IMimePart
|
||||
{
|
||||
$mime = $this->mimePartFactory->newInstance();
|
||||
$this->copyContentHeadersAndContent($part, $mime, true);
|
||||
return $mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies type headers (Content-Type, Content-Disposition,
|
||||
* Content-Transfer-Encoding) from the $from MimePart to $to. Attaches the
|
||||
* content resource handle of $from to $to, and loops over child parts,
|
||||
* removing them from $from and adding them to $to.
|
||||
*
|
||||
*/
|
||||
public function movePartContentAndChildren(IMimePart $from, IMimePart $to) : static
|
||||
{
|
||||
$this->copyContentHeadersAndContent($from, $to, true);
|
||||
if ($from->getChildCount() > 0) {
|
||||
foreach ($from->getChildIterator() as $child) {
|
||||
$from->removePart($child);
|
||||
$to->addChild($child);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the $part IMimePart with $replacement.
|
||||
*
|
||||
* Essentially removes $part from its parent, and adds $replacement in its
|
||||
* same position. If $part is the IMessage, then $part can't be removed and
|
||||
* replaced, and instead $replacement's type headers are copied to $message,
|
||||
* and any children below $replacement are added directly below $message.
|
||||
*/
|
||||
public function replacePart(IMessage $message, IMimePart $part, IMimePart $replacement) : static
|
||||
{
|
||||
$position = $message->removePart($replacement);
|
||||
if ($part === $message) {
|
||||
$this->movePartContentAndChildren($replacement, $message);
|
||||
return $this;
|
||||
}
|
||||
$parent = $part->getParent();
|
||||
$parent->addChild($replacement, $position);
|
||||
$parent->removePart($part);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
396
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/MultipartHelper.php
vendored
Normal file
396
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/MultipartHelper.php
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\IMultiPart;
|
||||
use ZBateson\MailMimeParser\Message\PartFilter;
|
||||
|
||||
/**
|
||||
* Provides various routines to manipulate and create multipart messages from an
|
||||
* existing message (e.g. to make space for attachments in a message, or to
|
||||
* change a simple message to a multipart/alternative one, etc...)
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MultipartHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var GenericHelper a GenericHelper instance
|
||||
*/
|
||||
private GenericHelper $genericHelper;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory,
|
||||
GenericHelper $genericHelper
|
||||
) {
|
||||
parent::__construct($mimePartFactory, $uuEncodedPartFactory);
|
||||
$this->genericHelper = $genericHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a unique boundary.
|
||||
*
|
||||
* @param string $mimeType first 3 characters of a multipart type are used,
|
||||
* e.g. REL for relative or ALT for alternative
|
||||
*/
|
||||
public function getUniqueBoundary(string $mimeType) : string
|
||||
{
|
||||
$type = \ltrim(\strtoupper(\preg_replace('/^(multipart\/(.{3}).*|.*)$/i', '$2-', $mimeType)), '-');
|
||||
return \uniqid('----=MMP-' . $type . '-', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique mime boundary and assigns it to the passed part's
|
||||
* Content-Type header with the passed mime type.
|
||||
*/
|
||||
public function setMimeHeaderBoundaryOnPart(IMimePart $part, string $mimeType) : static
|
||||
{
|
||||
$part->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
"$mimeType;\r\n\tboundary=\""
|
||||
. $this->getUniqueBoundary($mimeType) . '"'
|
||||
);
|
||||
$part->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the passed message as multipart/mixed.
|
||||
*
|
||||
* If the message has content, a new part is created and added as a child of
|
||||
* the message. The message's content and content headers are moved to the
|
||||
* new part.
|
||||
*/
|
||||
public function setMessageAsMixed(IMessage $message) : static
|
||||
{
|
||||
if ($message->hasContent()) {
|
||||
$part = $this->genericHelper->createNewContentPartFrom($message);
|
||||
$message->addChild($part, 0);
|
||||
}
|
||||
$this->setMimeHeaderBoundaryOnPart($message, 'multipart/mixed');
|
||||
$atts = $message->getAllAttachmentParts();
|
||||
if (!empty($atts)) {
|
||||
foreach ($atts as $att) {
|
||||
$att->notify();
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the passed message as multipart/alternative.
|
||||
*
|
||||
* If the message has content, a new part is created and added as a child of
|
||||
* the message. The message's content and content headers are moved to the
|
||||
* new part.
|
||||
*/
|
||||
public function setMessageAsAlternative(IMessage $message) : static
|
||||
{
|
||||
if ($message->hasContent()) {
|
||||
$part = $this->genericHelper->createNewContentPartFrom($message);
|
||||
$message->addChild($part, 0);
|
||||
}
|
||||
$this->setMimeHeaderBoundaryOnPart($message, 'multipart/alternative');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the passed $alternativePart for a part with the passed mime type
|
||||
* and returns its parent.
|
||||
*
|
||||
* Used for alternative mime types that have a multipart/mixed or
|
||||
* multipart/related child containing a content part of $mimeType, where
|
||||
* the whole mixed/related part should be removed.
|
||||
*
|
||||
* @param string $mimeType the content-type to find below $alternativePart
|
||||
* @param IMimePart $alternativePart The multipart/alternative part to look
|
||||
* under
|
||||
* @return bool|IMimePart false if a part is not found
|
||||
*/
|
||||
public function getContentPartContainerFromAlternative($mimeType, IMimePart $alternativePart) : bool|IMimePart
|
||||
{
|
||||
$part = $alternativePart->getPart(0, PartFilter::fromInlineContentType($mimeType));
|
||||
$contPart = null;
|
||||
do {
|
||||
if ($part === null) {
|
||||
return false;
|
||||
}
|
||||
$contPart = $part;
|
||||
$part = $part->getParent();
|
||||
} while ($part !== $alternativePart);
|
||||
return $contPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all parts of $mimeType from $alternativePart.
|
||||
*
|
||||
* If $alternativePart contains a multipart/mixed or multipart/relative part
|
||||
* with other parts of different content-types, the multipart part is
|
||||
* removed, and parts of different content-types can optionally be moved to
|
||||
* the main message part.
|
||||
*/
|
||||
public function removeAllContentPartsFromAlternative(
|
||||
IMessage $message,
|
||||
string $mimeType,
|
||||
IMimePart $alternativePart,
|
||||
bool $keepOtherContent
|
||||
) : bool {
|
||||
$rmPart = $this->getContentPartContainerFromAlternative($mimeType, $alternativePart);
|
||||
if ($rmPart === false) {
|
||||
return false;
|
||||
}
|
||||
if ($keepOtherContent && $rmPart->getChildCount() > 0) {
|
||||
$this->moveAllNonMultiPartsToMessageExcept($message, $rmPart, $mimeType);
|
||||
$alternativePart = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
}
|
||||
$message->removePart($rmPart);
|
||||
if ($alternativePart !== null && $alternativePart instanceof IMultiPart) {
|
||||
if ($alternativePart->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $alternativePart, $alternativePart->getChild(0));
|
||||
} elseif ($alternativePart->getChildCount() === 0) {
|
||||
$message->removePart($alternativePart);
|
||||
}
|
||||
}
|
||||
while ($message->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $message, $message->getChild(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mime part as a multipart/alternative and assigns the passed
|
||||
* $contentPart as a part below it before returning it.
|
||||
*
|
||||
* @return IMimePart the alternative part
|
||||
*/
|
||||
public function createAlternativeContentPart(IMessage $message, IMessagePart $contentPart) : IMimePart
|
||||
{
|
||||
$altPart = $this->mimePartFactory->newInstance();
|
||||
$this->setMimeHeaderBoundaryOnPart($altPart, 'multipart/alternative');
|
||||
$message->removePart($contentPart);
|
||||
$message->addChild($altPart, 0);
|
||||
$altPart->addChild($contentPart, 0);
|
||||
return $altPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves all parts under $from into this message except those with a
|
||||
* content-type equal to $exceptMimeType. If the message is not a
|
||||
* multipart/mixed message, it is set to multipart/mixed first.
|
||||
*/
|
||||
public function moveAllNonMultiPartsToMessageExcept(IMessage $message, IMimePart $from, string $exceptMimeType) : static
|
||||
{
|
||||
$parts = $from->getAllParts(function(IMessagePart $part) use ($exceptMimeType) {
|
||||
if ($part instanceof IMimePart && $part->isMultiPart()) {
|
||||
return false;
|
||||
}
|
||||
return \strcasecmp($part->getContentType(), $exceptMimeType) !== 0;
|
||||
});
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/mixed') !== 0) {
|
||||
$this->setMessageAsMixed($message);
|
||||
}
|
||||
foreach ($parts as $key => $part) {
|
||||
$from->removePart($part);
|
||||
$message->addChild($part);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the message to be a mime message for a non-mime (e.g. uuencoded
|
||||
* or unspecified) message. If the message has uuencoded attachments, sets
|
||||
* up the message as a multipart/mixed message and creates a separate
|
||||
* content part.
|
||||
*/
|
||||
public function enforceMime(IMessage $message) : static
|
||||
{
|
||||
if (!$message->isMime()) {
|
||||
if ($message->getAttachmentCount()) {
|
||||
$this->setMessageAsMixed($message);
|
||||
} else {
|
||||
$message->setRawHeader(HeaderConsts::CONTENT_TYPE, "text/plain;\r\n\tcharset=\"iso-8859-1\"");
|
||||
}
|
||||
$message->setRawHeader(HeaderConsts::MIME_VERSION, '1.0');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multipart/related part out of 'inline' children of $parent and
|
||||
* returns it.
|
||||
*/
|
||||
public function createMultipartRelatedPartForInlineChildrenOf(IMimePart $parent) : IMimePart
|
||||
{
|
||||
$relatedPart = $this->mimePartFactory->newInstance();
|
||||
$this->setMimeHeaderBoundaryOnPart($relatedPart, 'multipart/related');
|
||||
foreach ($parent->getChildParts(PartFilter::fromDisposition('inline')) as $part) {
|
||||
$parent->removePart($part);
|
||||
$relatedPart->addChild($part);
|
||||
}
|
||||
$parent->addChild($relatedPart, 0);
|
||||
return $relatedPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an alternative inline part in the message and returns it if one
|
||||
* exists.
|
||||
*
|
||||
* If the passed $mimeType is text/plain, searches for a text/html part.
|
||||
* Otherwise searches for a text/plain part to return.
|
||||
*
|
||||
* @return IMimePart or null if not found
|
||||
*/
|
||||
public function findOtherContentPartFor(IMessage $message, string $mimeType) : ?IMimePart
|
||||
{
|
||||
$altPart = $message->getPart(
|
||||
0,
|
||||
PartFilter::fromInlineContentType(($mimeType === 'text/plain') ? 'text/html' : 'text/plain')
|
||||
);
|
||||
if ($altPart !== null && $altPart->getParent() !== null && $altPart->getParent()->isMultiPart()) {
|
||||
$altPartParent = $altPart->getParent();
|
||||
if ($altPartParent->getChildCount(PartFilter::fromDisposition('inline')) !== 1) {
|
||||
$altPart = $this->createMultipartRelatedPartForInlineChildrenOf($altPartParent);
|
||||
}
|
||||
}
|
||||
return $altPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new content part for the passed mimeType and charset, making
|
||||
* space by creating a multipart/alternative if needed
|
||||
*/
|
||||
public function createContentPartForMimeType(IMessage $message, string $mimeType, string $charset) : IMimePart
|
||||
{
|
||||
$mimePart = $this->mimePartFactory->newInstance();
|
||||
$mimePart->setRawHeader(HeaderConsts::CONTENT_TYPE, "$mimeType;\r\n\tcharset=\"$charset\"");
|
||||
$mimePart->setRawHeader(HeaderConsts::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
|
||||
|
||||
$this->enforceMime($message);
|
||||
$altPart = $this->findOtherContentPartFor($message, $mimeType);
|
||||
|
||||
if ($altPart === $message) {
|
||||
$this->setMessageAsAlternative($message);
|
||||
$message->addChild($mimePart);
|
||||
} elseif ($altPart !== null) {
|
||||
$mimeAltPart = $this->createAlternativeContentPart($message, $altPart);
|
||||
$mimeAltPart->addChild($mimePart, 1);
|
||||
} else {
|
||||
$message->addChild($mimePart, 0);
|
||||
}
|
||||
|
||||
return $mimePart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a IMimePart for the passed content and options as an
|
||||
* attachment.
|
||||
*
|
||||
* @param string|resource|\Psr\Http\Message\StreamInterface $resource
|
||||
*/
|
||||
public function createAndAddPartForAttachment(
|
||||
IMessage $message,
|
||||
$resource,
|
||||
string $mimeType,
|
||||
string $disposition,
|
||||
?string $filename = null,
|
||||
string $encoding = 'base64'
|
||||
) : IMessagePart {
|
||||
if ($filename === null) {
|
||||
$filename = 'file' . \uniqid();
|
||||
}
|
||||
|
||||
$safe = \iconv('UTF-8', 'US-ASCII//translit//ignore', $filename);
|
||||
if ($message->isMime()) {
|
||||
$part = $this->mimePartFactory->newInstance();
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TRANSFER_ENCODING, $encoding);
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/mixed') !== 0) {
|
||||
$this->setMessageAsMixed($message);
|
||||
}
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TYPE, "$mimeType;\r\n\tname=\"$safe\"");
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_DISPOSITION, "$disposition;\r\n\tfilename=\"$safe\"");
|
||||
} else {
|
||||
$part = $this->uuEncodedPartFactory->newInstance();
|
||||
$part->setFilename($safe);
|
||||
}
|
||||
$part->setContent($resource);
|
||||
$message->addChild($part);
|
||||
return $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the content part of the message with the passed mime type. If
|
||||
* there is a remaining content part and it is an alternative part of the
|
||||
* main message, the content part is moved to the message part.
|
||||
*
|
||||
* If the content part is part of an alternative part beneath the message,
|
||||
* the alternative part is replaced by the remaining content part,
|
||||
* optionally keeping other parts if $keepOtherContent is set to true.
|
||||
*
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeAllContentPartsByMimeType(IMessage $message, string $mimeType, bool $keepOtherContent = false) : bool
|
||||
{
|
||||
$alt = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
if ($alt !== null) {
|
||||
return $this->removeAllContentPartsFromAlternative($message, $mimeType, $alt, $keepOtherContent);
|
||||
}
|
||||
$message->removeAllParts(PartFilter::fromInlineContentType($mimeType));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the 'inline' part with the passed contentType, at the given index
|
||||
* defaulting to the first
|
||||
*
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removePartByMimeType(IMessage $message, string $mimeType, int $index = 0) : bool
|
||||
{
|
||||
$parts = $message->getAllParts(PartFilter::fromInlineContentType($mimeType));
|
||||
$alt = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
if ($parts === null || !isset($parts[$index])) {
|
||||
return false;
|
||||
} elseif (\count($parts) === 1) {
|
||||
return $this->removeAllContentPartsByMimeType($message, $mimeType, true);
|
||||
}
|
||||
$part = $parts[$index];
|
||||
$message->removePart($part);
|
||||
if ($alt !== null && $alt->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $alt, $alt->getChild(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Either creates a mime part or sets the existing mime part with the passed
|
||||
* mimeType to $strongOrHandle.
|
||||
*
|
||||
* @param string|resource $stringOrHandle
|
||||
*/
|
||||
public function setContentPartForMimeType(IMessage $message, string $mimeType, mixed $stringOrHandle, string $charset) : static
|
||||
{
|
||||
$part = ($mimeType === 'text/html') ? $message->getHtmlPart() : $message->getTextPart();
|
||||
if ($part === null) {
|
||||
$part = $this->createContentPartForMimeType($message, $mimeType, $charset);
|
||||
} else {
|
||||
$contentType = $part->getContentType();
|
||||
if ($part instanceof IMimePart) {
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TYPE, "$contentType;\r\n\tcharset=\"$charset\"");
|
||||
}
|
||||
}
|
||||
$part->setContent($stringOrHandle);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
159
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/PrivacyHelper.php
vendored
Normal file
159
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/PrivacyHelper.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
|
||||
/**
|
||||
* Provides routines to set or retrieve the signature part of a signed message.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PrivacyHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var GenericHelper a GenericHelper instance
|
||||
*/
|
||||
private GenericHelper $genericHelper;
|
||||
|
||||
/**
|
||||
* @var MultipartHelper a MultipartHelper instance
|
||||
*/
|
||||
private MultipartHelper $multipartHelper;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory,
|
||||
GenericHelper $genericHelper,
|
||||
MultipartHelper $multipartHelper
|
||||
) {
|
||||
parent::__construct($mimePartFactory, $uuEncodedPartFactory);
|
||||
$this->genericHelper = $genericHelper;
|
||||
$this->multipartHelper = $multipartHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* The passed message is set as multipart/signed, and a new part is created
|
||||
* below it with content headers, content and children copied from the
|
||||
* message.
|
||||
*
|
||||
* @param string $micalg
|
||||
* @param string $protocol
|
||||
*/
|
||||
public function setMessageAsMultipartSigned(IMessage $message, $micalg, $protocol) : static
|
||||
{
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/signed') !== 0) {
|
||||
$this->multipartHelper->enforceMime($message);
|
||||
$messagePart = $this->mimePartFactory->newInstance();
|
||||
$this->genericHelper->movePartContentAndChildren($message, $messagePart);
|
||||
$message->addChild($messagePart);
|
||||
$boundary = $this->multipartHelper->getUniqueBoundary('multipart/signed');
|
||||
$message->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
"multipart/signed;\r\n\tboundary=\"$boundary\";\r\n\tmicalg=\"$micalg\"; protocol=\"$protocol\""
|
||||
);
|
||||
}
|
||||
$this->overwrite8bitContentEncoding($message);
|
||||
$this->setSignature($message, 'Empty');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the signature of the message to $body, creating a signature part if
|
||||
* one doesn't exist.
|
||||
*
|
||||
* @param string $body
|
||||
*/
|
||||
public function setSignature(IMessage $message, $body) : static
|
||||
{
|
||||
$signedPart = $message->getSignaturePart();
|
||||
if ($signedPart === null) {
|
||||
$signedPart = $this->mimePartFactory->newInstance();
|
||||
$message->addChild($signedPart);
|
||||
}
|
||||
$signedPart->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
$message->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'protocol')
|
||||
);
|
||||
$signedPart->setContent($body);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over parts of the message and sets the content-transfer-encoding
|
||||
* header to quoted-printable for text/* mime parts, and to base64
|
||||
* otherwise for parts that are '8bit' encoded.
|
||||
*
|
||||
* Used for multipart/signed messages which doesn't support 8bit transfer
|
||||
* encodings.
|
||||
*/
|
||||
public function overwrite8bitContentEncoding(IMessage $message) : static
|
||||
{
|
||||
$parts = $message->getAllParts(function(IMessagePart $part) {
|
||||
return \strcasecmp($part->getContentTransferEncoding(), '8bit') === 0;
|
||||
});
|
||||
foreach ($parts as $part) {
|
||||
$contentType = \strtolower($part->getContentType());
|
||||
$part->setRawHeader(
|
||||
HeaderConsts::CONTENT_TRANSFER_ENCODING,
|
||||
($contentType === 'text/plain' || $contentType === 'text/html') ?
|
||||
'quoted-printable' :
|
||||
'base64'
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream that can be used to read the content part of a signed
|
||||
* message, which can be used to sign an email or verify a signature.
|
||||
*
|
||||
* The method simply returns the stream for the first child. No
|
||||
* verification of whether the message is in fact a signed message is
|
||||
* performed.
|
||||
*
|
||||
* Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
|
||||
* replace new lines.
|
||||
*
|
||||
* @return ?StreamInterface null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageStream(IMessage $message) : ?StreamInterface
|
||||
{
|
||||
$child = $message->getChild(0);
|
||||
if ($child !== null) {
|
||||
return $child->getStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing the entire body (content) of a signed message
|
||||
* for verification or calculating a signature.
|
||||
*
|
||||
* Non-CRLF new lines are replaced to always be CRLF.
|
||||
*
|
||||
* @return ?string null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageAsString(IMessage $message) : ?string
|
||||
{
|
||||
$stream = $this->getSignedMessageStream($message);
|
||||
if ($stream !== null) {
|
||||
return \preg_replace(
|
||||
'/\r\n|\r|\n/',
|
||||
"\r\n",
|
||||
$stream->getContents()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
386
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMessagePart.php
vendored
Normal file
386
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMessagePart.php
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use SplSubject;
|
||||
use ZBateson\MailMimeParser\IErrorBag;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* An interface representing a single part of an email.
|
||||
*
|
||||
* The base type for a message or any child part of a message. The part may
|
||||
* contain content, have a parent, and identify the type of content (e.g.
|
||||
* mime-type or charset) agnostically.
|
||||
*
|
||||
* The interface extends SplSubject -- any modifications to a message must
|
||||
* notify any attached observers.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMessagePart extends IErrorBag, SplSubject
|
||||
{
|
||||
/**
|
||||
* Returns this part's parent.
|
||||
*/
|
||||
public function getParent() : ?IMimePart;
|
||||
|
||||
/**
|
||||
* Returns true if the part contains a 'body' (content).
|
||||
*
|
||||
*/
|
||||
public function hasContent() : bool;
|
||||
|
||||
/**
|
||||
* Returns true if the content of this part is plain text.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool;
|
||||
|
||||
/**
|
||||
* Returns the mime type of the content, or $default if one is not set.
|
||||
*
|
||||
* @param string $default Optional override for the default return value of
|
||||
* 'text/plain.
|
||||
* @return string the mime type
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string;
|
||||
|
||||
/**
|
||||
* Returns the charset of the content, or null if not applicable/defined.
|
||||
*
|
||||
* @return string|null the charset
|
||||
*/
|
||||
public function getCharset() : ?string;
|
||||
|
||||
/**
|
||||
* Returns the content's disposition, or returns the value of $default if
|
||||
* not defined.
|
||||
*
|
||||
* @param string $default Optional default value to return if not
|
||||
* applicable/defined
|
||||
* @return string|null the disposition.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the content transfer encoding used to encode the content on this
|
||||
* part, or the value of $default if not defined.
|
||||
*
|
||||
* @param ?string $default Optional default value to return if not
|
||||
* applicable/defined
|
||||
* @return string|null the transfer encoding defined for the part.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part, or null if not defined.
|
||||
*
|
||||
* @return string|null the content ID.
|
||||
*/
|
||||
public function getContentId() : ?string;
|
||||
|
||||
/**
|
||||
* Returns a filename for the part if one is defined, or null otherwise.
|
||||
*
|
||||
* @return string|null the file name
|
||||
*/
|
||||
public function getFilename() : ?string;
|
||||
|
||||
/**
|
||||
* Returns true if the current part is a mime part.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool;
|
||||
|
||||
/**
|
||||
* Overrides the default character set used for reading content from content
|
||||
* streams in cases where a user knows the source charset is not what is
|
||||
* specified.
|
||||
*
|
||||
* If set, the returned value from {@see IMessagePart::getCharset()} must be
|
||||
* ignored during subsequent read operations and streams created out of this
|
||||
* part's content.
|
||||
*
|
||||
* Note that setting an override on an
|
||||
* {@see \ZBateson\MailMimeParser\IMessage} and calling getTextStream,
|
||||
* getTextContent, getHtmlStream or getHtmlContent will not be applied to
|
||||
* those sub-parts, unless the text/html part is the IMessage itself.
|
||||
* Instead, {@see \ZBateson\MailMimeParser\IMessage::getTextPart()} should
|
||||
* be called, and setCharsetOverride called on the returned IMessagePart.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @param string $charsetOverride the actual charset of the content.
|
||||
* @param bool $onlyIfNoCharset if true, $charsetOverride is used only if
|
||||
* getCharset returns null.
|
||||
*/
|
||||
public function setCharsetOverride(string $charsetOverride, bool $onlyIfNoCharset = false) : static;
|
||||
|
||||
/**
|
||||
* Returns the StreamInterface for the part's content or null if the part
|
||||
* doesn't have a content section.
|
||||
*
|
||||
* To get a stream without charset conversion if you know the part's content
|
||||
* contains a binary stream, call {@see self::getBinaryContentStream()}
|
||||
* instead.
|
||||
*
|
||||
* The library automatically handles decoding and charset conversion (to the
|
||||
* target passed $charset) based on the part's transfer encoding as returned
|
||||
* by {@see IMessagePart::getContentTransferEncoding()} and the part's
|
||||
* charset as returned by {@see IMessagePart::getCharset()}. The returned
|
||||
* stream is ready to be read from directly.
|
||||
*
|
||||
* Note that the returned Stream is a shared object. If called multiple
|
||||
* times with the same $charset, and the value of the part's
|
||||
* Content-Transfer-Encoding header has not changed, the stream will be
|
||||
* rewound. This would affect other existing variables referencing the
|
||||
* stream, for example:
|
||||
*
|
||||
* ```php
|
||||
* // assuming $part is a part containing the following
|
||||
* // string for its content: '12345678'
|
||||
* $stream = $part->getContentStream();
|
||||
* $someChars = $part->read(4);
|
||||
*
|
||||
* $stream2 = $part->getContentStream();
|
||||
* $moreChars = $part->read(4);
|
||||
* echo ($someChars === $moreChars); //1
|
||||
* ```
|
||||
*
|
||||
* In this case the Stream was rewound, and $stream's second call to read 4
|
||||
* bytes reads the same first 4.
|
||||
*
|
||||
* @see IMessagePart::getBinaryContentStream() to get the content stream
|
||||
* without any charset conversions.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @see IMessagePart::setCharsetOverride() to override the charset of the
|
||||
* content and ignore the charset returned from calling
|
||||
* IMessagePart::getCharset() when reading.
|
||||
* @param string $charset Optional charset for the returned stream.
|
||||
* @return StreamInterface|null the stream
|
||||
*/
|
||||
public function getContentStream(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns the raw data stream for the current part, if it exists, or null
|
||||
* if there's no content associated with the stream.
|
||||
*
|
||||
* This is basically the same as calling
|
||||
* {@see IMessagePart::getContentStream()}, except no automatic charset
|
||||
* conversion is done. Note that for non-text streams, this doesn't have an
|
||||
* effect, as charset conversion is not performed in that case, and is
|
||||
* useful only when:
|
||||
*
|
||||
* - The charset defined is not correct, and the conversion produces errors;
|
||||
* or
|
||||
* - You'd like to read the raw contents without conversion, for instance to
|
||||
* save it to file or allow a user to download it as-is (in a download
|
||||
* link for example).
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream with
|
||||
* charset conversions applied.
|
||||
* @see IMessagePart::getBinaryContentResourceHandle() to get a resource
|
||||
* handle instead.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @return StreamInterface|null the stream
|
||||
*/
|
||||
public function getBinaryContentStream() : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns a resource handle for the content's raw data stream, or null if
|
||||
* the part doesn't have a content stream.
|
||||
*
|
||||
* The method wraps a call to {@see IMessagePart::getBinaryContentStream()}
|
||||
* and returns a resource handle for the returned Stream.
|
||||
*
|
||||
* @see IMessagePart::getBinaryContentStream() to get a stream instead.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @return resource|null the resource
|
||||
*/
|
||||
public function getBinaryContentResourceHandle() : mixed;
|
||||
|
||||
/**
|
||||
* Saves the binary content of the stream to the passed file, resource or
|
||||
* stream.
|
||||
*
|
||||
* Note that charset conversion is not performed in this case, and the
|
||||
* contents of the part are saved in their binary format as transmitted (but
|
||||
* after any content-transfer decoding is performed). {@see
|
||||
* IMessagePart::getBinaryContentStream()} for a more detailed description
|
||||
* of the stream.
|
||||
*
|
||||
* If the passed parameter is a string, it's assumed to be a filename to
|
||||
* write to. The file is opened in 'w+' mode, and closed before returning.
|
||||
*
|
||||
* When passing a resource or Psr7 Stream, the resource is not closed, nor
|
||||
* rewound.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream with
|
||||
* charset conversions applied.
|
||||
* @see IMessagePart::getBinaryContentStream() to get the content as a
|
||||
* binary stream.
|
||||
* @see IMessagePart::getBinaryContentResourceHandle() to get the content as
|
||||
* a resource handle.
|
||||
* @param string|resource|StreamInterface $filenameResourceOrStream
|
||||
*/
|
||||
public function saveContent($filenameResourceOrStream) : static;
|
||||
|
||||
/**
|
||||
* Shortcut to reading stream content and assigning it to a string. Returns
|
||||
* null if the part doesn't have a content stream.
|
||||
*
|
||||
* The returned string is encoded to the passed $charset character encoding.
|
||||
*
|
||||
* @see IMessagePart::getContentStream()
|
||||
* @param string $charset the target charset for the returned string
|
||||
* @return ?string the content
|
||||
*/
|
||||
public function getContent(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string;
|
||||
|
||||
/**
|
||||
* Attaches the stream or resource handle for the part's content. The
|
||||
* stream is closed when another stream is attached, or the MimePart is
|
||||
* destroyed.
|
||||
*
|
||||
* @see IMessagePart::setContent() to pass a string as the content.
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::detachContentStream() to detach the content stream.
|
||||
* @param StreamInterface $stream the content
|
||||
* @param string $streamCharset the charset of $stream
|
||||
*/
|
||||
public function attachContentStream(StreamInterface $stream, string $streamCharset = MailMimeParser::DEFAULT_CHARSET) : static;
|
||||
|
||||
/**
|
||||
* Detaches the content stream.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::attachContentStream() to attach a content stream.
|
||||
*/
|
||||
public function detachContentStream() : static;
|
||||
|
||||
/**
|
||||
* Sets the content of the part to the passed string, resource, or stream.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::attachContentStream() to attach a content stream.
|
||||
* @see IMessagePart::detachContentStream() to detach the content stream.
|
||||
* @param string|resource|StreamInterface $resource the content.
|
||||
* @param string $resourceCharset the charset of the passed $resource.
|
||||
*/
|
||||
public function setContent($resource, string $resourceCharset = MailMimeParser::DEFAULT_CHARSET) : static;
|
||||
|
||||
/**
|
||||
* Returns a resource handle for the string representation of this part,
|
||||
* containing its headers, content and children. For an IMessage, this
|
||||
* would be the entire RFC822 (or greater) email.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be returned. Otherwise a stream representation of
|
||||
* the part including its modifications should be returned. This insures
|
||||
* that an unmodified, signed message could be passed on that way even after
|
||||
* parsing and reading.
|
||||
*
|
||||
* The returned stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* @see IMessagePart::getStream() to get a Psr7 StreamInterface instead of a
|
||||
* resource handle.
|
||||
* @see IMessagePart::__toString() to write the part to a string and return
|
||||
* it.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @return resource the resource handle containing the part.
|
||||
*/
|
||||
public function getResourceHandle() : mixed;
|
||||
|
||||
/**
|
||||
* Returns a Psr7 StreamInterface for the string representation of this
|
||||
* part, containing its headers, content and children.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be returned. Otherwise a stream representation of
|
||||
* the part including its modifications should be returned. This insures
|
||||
* that an unmodified, signed message could be passed on that way even after
|
||||
* parsing and reading.
|
||||
*
|
||||
* The returned stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessagePart::__toString() to write the part to a string and return
|
||||
* it.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @return StreamInterface the stream containing the part.
|
||||
*/
|
||||
public function getStream() : StreamInterface;
|
||||
|
||||
/**
|
||||
* Writes a string representation of this part, including its headers,
|
||||
* content and children to the passed file, resource, or stream.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be written to the file. Otherwise a stream
|
||||
* representation of the part including its modifications should be written.
|
||||
* This insures that an unmodified, signed message could be passed on this
|
||||
* way even after parsing and reading.
|
||||
*
|
||||
* The written stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* If the passed $filenameResourceOrStream is a string, it's assumed to be a
|
||||
* filename to write to.
|
||||
*
|
||||
* When passing a resource or Psr7 Stream, the resource is not closed, nor
|
||||
* rewound after being written to.
|
||||
*
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessagePart::__toString() to get the part in a string.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @param string|resource|StreamInterface $filenameResourceOrStream the
|
||||
* file, resource, or stream to write to.
|
||||
* @param string $filemode Optional filemode to open a file in (if
|
||||
* $filenameResourceOrStream is a string)
|
||||
*/
|
||||
public function save(mixed $filenameResourceOrStream, string $filemode = 'w+') : static;
|
||||
|
||||
/**
|
||||
* Returns the message/part as a string, containing its headers, content and
|
||||
* children.
|
||||
*
|
||||
* Convenience method for calling getContents() on
|
||||
* {@see IMessagePart::getStream()}.
|
||||
*
|
||||
* @see IMessagePart::getStream() to get a Psr7 StreamInterface instead of a
|
||||
* string.
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
*/
|
||||
public function __toString() : string;
|
||||
}
|
||||
323
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMimePart.php
vendored
Normal file
323
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMimePart.php
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
|
||||
/**
|
||||
* An interface representation of any MIME email part.
|
||||
*
|
||||
* A MIME part may contain any combination of headers, content and children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMimePart extends IMultiPart
|
||||
{
|
||||
/**
|
||||
* Returns true if this part's content type matches multipart/*
|
||||
*/
|
||||
public function isMultiPart() : bool;
|
||||
|
||||
/**
|
||||
* Returns true if this part is the 'signature' part of a signed message.
|
||||
*/
|
||||
public function isSignaturePart() : bool;
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name.
|
||||
*
|
||||
* If the optional $offset is passed, and multiple headers exist with the
|
||||
* same name, the one at the passed offset is returned.
|
||||
*
|
||||
* Note that mime header names aren't case sensitive, and the '-' character
|
||||
* is ignored, so ret
|
||||
*
|
||||
* If a header with the given $name and $offset doesn't exist, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMimePart::getHeaderAs() to parse a header into a provided IHeader
|
||||
* type and return it.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @param string $name The name of the header to retrieve.
|
||||
* @param int $offset Optional offset if there are multiple headers with the
|
||||
* given name.
|
||||
* @return ?IHeader the header object if it exists, or null if not
|
||||
*/
|
||||
public function getHeader(string $name, int $offset = 0) : ?IHeader;
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, using the
|
||||
* passed $iHeaderClass to construct it.
|
||||
*
|
||||
* If the optional $offset is passed, and multiple headers exist with the
|
||||
* same name, the one at the passed offset is returned.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive, and the '-' character is
|
||||
*
|
||||
* If a header with the given $name and $offset doesn't exist, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @param string $name The name of the header to retrieve.
|
||||
* @param int $offset Optional offset if there are multiple headers with the
|
||||
* given name.
|
||||
* @return ?IHeader the header object
|
||||
*/
|
||||
public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader;
|
||||
|
||||
/**
|
||||
* Returns an array of all headers in this part.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @return IHeader[] an array of header objects
|
||||
*/
|
||||
public function getAllHeaders() : array;
|
||||
|
||||
/**
|
||||
* Returns an array of headers that match the passed name.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @return IHeader[] an array of header objects
|
||||
*/
|
||||
public function getAllHeadersByName(string $name) : array;
|
||||
|
||||
/**
|
||||
* Returns a two dimensional string array of all headers for the mime part
|
||||
* with the first element holding the name, and the second its raw string
|
||||
* value:
|
||||
*
|
||||
* [ [ '1st-Header-Name', 'Header Value' ], [ '2nd-Header-Name', 'Header Value' ] ]
|
||||
*
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @return string[][] an array of raw headers
|
||||
*/
|
||||
public function getRawHeaders() : array;
|
||||
|
||||
/**
|
||||
* Returns an iterator to all headers in this part. Each returned element
|
||||
* is an array with its first element set to the header's name, and the
|
||||
* second to its raw value:
|
||||
*
|
||||
* [ 'Header-Name', 'Header Value' ]
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @return Traversable<array<string>> an iterator for raw headers
|
||||
*/
|
||||
public function getRawHeaderIterator() : Traversable;
|
||||
|
||||
/**
|
||||
* Returns the string value for the header with the given $name, or null if
|
||||
* the header doesn't exist and no alternative $defaultValue is passed.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @param string $name The name of the header
|
||||
* @param ?string $defaultValue Optional default value to return if the
|
||||
* header doesn't exist on this part.
|
||||
* @return string|null the value of the header
|
||||
*/
|
||||
public function getHeaderValue(string $name, ?string $defaultValue = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the value of the parameter named $param on a header with the
|
||||
* passed $header name, or null if the parameter doesn't exist and a
|
||||
* $defaultValue isn't passed.
|
||||
*
|
||||
* Only headers of type
|
||||
* {@see \ZBateson\MailMimeParser\Header\ParameterHeader} have parameters.
|
||||
* Content-Type and Content-Disposition are examples of headers with
|
||||
* parameters. "Charset" is a common parameter of Content-Type.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @param string $header The name of the header.
|
||||
* @param string $param The name of the parameter.
|
||||
* @param ?string $defaultValue Optional default value to return if the
|
||||
* parameter doesn't exist.
|
||||
* @return string|null The value of the parameter.
|
||||
*/
|
||||
public function getHeaderParameter(string $header, string $param, ?string $defaultValue = null) : ?string;
|
||||
|
||||
/**
|
||||
* Adds a header with the given $name and $value. An optional $offset may
|
||||
* be passed, which will overwrite a header if one exists with the given
|
||||
* name and offset only. Otherwise a new header is added. The passed
|
||||
* $offset may be ignored in that case if it doesn't represent the next
|
||||
* insert position for the header with the passed name... instead it would
|
||||
* be 'pushed' on at the next position.
|
||||
*
|
||||
* ```
|
||||
* $part = $myMimePart;
|
||||
* $part->setRawHeader('New-Header', 'value');
|
||||
* echo $part->getHeaderValue('New-Header'); // 'value'
|
||||
*
|
||||
* $part->setRawHeader('New-Header', 'second', 4);
|
||||
* echo is_null($part->getHeader('New-Header', 4)); // '1' (true)
|
||||
* echo $part->getHeader('New-Header', 1)
|
||||
* ->getValue(); // 'second'
|
||||
* ```
|
||||
*
|
||||
* A new {@see \ZBateson\MailMimeParser\Header\IHeader} object is created
|
||||
* from the passed value. No processing on the passed string is performed,
|
||||
* and so the passed name and value must be formatted correctly according to
|
||||
* related RFCs. In particular, be careful to encode non-ascii data, to
|
||||
* keep lines under 998 characters in length, and to follow any special
|
||||
* formatting required for the type of header.
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the new header, e.g. 'Content-Type'.
|
||||
* @param ?string $value The raw value of the new header.
|
||||
* @param int $offset An optional offset, defaulting to '0' and therefore
|
||||
* overriding the first header of the given $name if one exists.
|
||||
*/
|
||||
public function setRawHeader(string $name, ?string $value, int $offset = 0) : static;
|
||||
|
||||
/**
|
||||
* Adds a header with the given $name and $value.
|
||||
*
|
||||
* Note: If a header with the passed name already exists, a new header is
|
||||
* created with the same name. This should only be used when that is
|
||||
* intentional - in most cases {@see IMimePart::setRawHeader()} should be
|
||||
* called instead.
|
||||
*
|
||||
* A new {@see \ZBateson\MailMimeParser\Header\IHeader} object is created
|
||||
* from the passed value. No processing on the passed string is performed,
|
||||
* and so the passed name and value must be formatted correctly according to
|
||||
* related RFCs. In particular, be careful to encode non-ascii data, to
|
||||
* keep lines under 998 characters in length, and to follow any special
|
||||
* formatting required for the type of header.
|
||||
*
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the header
|
||||
* @param string $value The raw value of the header.
|
||||
*/
|
||||
public function addRawHeader(string $name, string $value) : static;
|
||||
|
||||
/**
|
||||
* Removes all headers from this part with the passed name.
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the header(s) to remove.
|
||||
*/
|
||||
public function removeHeader(string $name) : static;
|
||||
|
||||
/**
|
||||
* Removes a single header with the passed name (in cases where more than
|
||||
* one may exist, and others should be preserved).
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @param string $name The name of the header to remove
|
||||
* @param int $offset Optional offset of the header to remove (defaults to
|
||||
* 0 -- the first header).
|
||||
*/
|
||||
public function removeSingleHeader(string $name, int $offset = 0) : static;
|
||||
}
|
||||
292
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMultiPart.php
vendored
Normal file
292
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMultiPart.php
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* An interface representing a message part that contains children.
|
||||
*
|
||||
* An IMultiPart object may have any number of child parts, or may be a child
|
||||
* itself with its own parent or parents.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMultiPart extends IMessagePart
|
||||
{
|
||||
/**
|
||||
* Returns the part at the given 0-based index for this part (part 0) and
|
||||
* all parts under it, or null if not found with the passed filter function.
|
||||
*
|
||||
* Note that the first part returned is the current part itself. This is
|
||||
* usually desirable for queries with a passed filter, e.g. looking for an
|
||||
* part with a specific Content-Type that may be satisfied by the current
|
||||
* part.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @param int $index The 0-based index (0 being this part if $fnFilter is
|
||||
* null or this part is satisfied by the filter).
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart|null A matching part, or null if not found.
|
||||
*/
|
||||
public function getPart(int $index, ?callable $fnFilter = null) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns the current part, all child parts, and child parts of all
|
||||
* children optionally filtering them with the provided PartFilter.
|
||||
*
|
||||
* Note that the first part returned is the current part itself. This is
|
||||
* often desirable for queries with a passed filter, e.g. looking for an
|
||||
* IMessagePart with a specific Content-Type that may be satisfied by the
|
||||
* current part.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart[] An array of matching parts.
|
||||
*/
|
||||
public function getAllParts(?callable $fnFilter = null) : array;
|
||||
|
||||
/**
|
||||
* Returns the total number of parts in this and all children.
|
||||
*
|
||||
* Note that the current part is considered, so the minimum getPartCount is
|
||||
* 1 without a filter.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of matching parts.
|
||||
*/
|
||||
public function getPartCount(?callable $fnFilter = null) : int;
|
||||
|
||||
/**
|
||||
* Returns the direct child at the given 0-based index and optional filter,
|
||||
* or null if none exist or do not match.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @param int $index 0-based index
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart|null The matching direct child part or null if not
|
||||
* found.
|
||||
*/
|
||||
public function getChild(int $index, ?callable $fnFilter = null) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns an array of all direct child parts, optionally filtering them
|
||||
* with a passed callable.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart[] An array of matching child parts.
|
||||
*/
|
||||
public function getChildParts(?callable $fnFilter = null) : array;
|
||||
|
||||
/**
|
||||
* Returns the number of direct children under this part (optionally
|
||||
* counting only filtered items if a callable filter is passed).
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of children, or number of children matching the
|
||||
* the passed filtering callable.
|
||||
*/
|
||||
public function getChildCount(?callable $fnFilter = null) : int;
|
||||
|
||||
/**
|
||||
* Returns a \RecursiveIterator of child parts.
|
||||
*
|
||||
* The {@see https://www.php.net/manual/en/class.recursiveiterator.php \RecursiveIterator}
|
||||
* allows iterating over direct children, or using
|
||||
* a {@see https://www.php.net/manual/en/class.recursiveiteratoriterator.php \RecursiveIteratorIterator}
|
||||
* to iterate over direct children, and all their children.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/class.recursiveiterator.php
|
||||
* RecursiveIterator
|
||||
* @see https://www.php.net/manual/en/class.recursiveiteratoriterator.php
|
||||
* RecursiveIteratorIterator
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @return RecursiveIterator<IMessagePart>
|
||||
*/
|
||||
public function getChildIterator() : RecursiveIterator;
|
||||
|
||||
/**
|
||||
* Returns the part that has a content type matching the passed mime type at
|
||||
* the given index, or null if there are no matching parts.
|
||||
*
|
||||
* Creates a filter that looks at the return value of
|
||||
* {@see IMessagePart::getContentType()} for all parts (including the
|
||||
* current part) and returns a matching one at the given 0-based index.
|
||||
*
|
||||
* @see IMultiPart::getAllPartsByMimeType() to get all parts that match a
|
||||
* mime type.
|
||||
* @see IMultiPart::getCountOfPartsByMimeType() to get a count of parts with
|
||||
* a mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @param int $index Optional 0-based index (defaulting to '0').
|
||||
* @return IMessagePart|null The part.
|
||||
*/
|
||||
public function getPartByMimeType(string $mimeType, int $index = 0) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns an array of all parts that have a content type matching the
|
||||
* passed mime type.
|
||||
*
|
||||
* Creates a filter that looks at the return value of
|
||||
* {@see IMessagePart::getContentType()} for all parts (including the
|
||||
* current part), returning an array of matching parts.
|
||||
*
|
||||
* @see IMultiPart::getPartByMimeType() to get a part by mime type.
|
||||
* @see IMultiPart::getCountOfPartsByMimeType() to get a count of parts with
|
||||
* a mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @return IMessagePart[] An array of matching parts.
|
||||
*/
|
||||
public function getAllPartsByMimeType(string $mimeType) : array;
|
||||
|
||||
/**
|
||||
* Returns the number of parts that have content types matching the passed
|
||||
* mime type.
|
||||
*
|
||||
* @see IMultiPart::getPartByMimeType() to get a part by mime type.
|
||||
* @see IMultiPart::getAllPartsByMimeType() to get all parts that match a
|
||||
* mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @return int The number of matching parts.
|
||||
*/
|
||||
public function getCountOfPartsByMimeType(string $mimeType) : int;
|
||||
|
||||
/**
|
||||
* Returns a part that has the given Content ID, or null if not found.
|
||||
*
|
||||
* Calls {@see IMessagePart::getContentId()} to find a matching part.
|
||||
*
|
||||
* @param string $contentId The content ID to find a part for.
|
||||
* @return IMessagePart|null The matching part.
|
||||
*/
|
||||
public function getPartByContentId(string $contentId) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Registers the passed part as a child of the current part.
|
||||
*
|
||||
* If the $position parameter is non-null, adds the part at the passed
|
||||
* position index, otherwise adds it as the last child.
|
||||
*
|
||||
* @param MessagePart $part The part to add.
|
||||
* @param int $position Optional insertion position 0-based index.
|
||||
*/
|
||||
public function addChild(MessagePart $part, ?int $position = null) : static;
|
||||
|
||||
/**
|
||||
* Removes the child part from this part and returns its previous position
|
||||
* or null if it wasn't found.
|
||||
*
|
||||
* Note that if the part is not a direct child of this part, the returned
|
||||
* position is its index within its parent (calls removePart on its direct
|
||||
* parent).
|
||||
*
|
||||
* This also means that parts from unrelated parts/messages could be removed
|
||||
* by a call to removePart -- it will always remove the part from its parent
|
||||
* if it has one, essentially calling
|
||||
* ```php $part->getParent()->removePart(); ```.
|
||||
*
|
||||
* @param IMessagePart $part The part to remove
|
||||
* @return int|null The previous index position of the part within its old
|
||||
* parent.
|
||||
*/
|
||||
public function removePart(IMessagePart $part) : ?int;
|
||||
|
||||
/**
|
||||
* Removes all parts below the current part. If a callable filter is
|
||||
* passed, removes only those matching the passed filter. The number of
|
||||
* removed parts is returned.
|
||||
*
|
||||
* Note: the current part will not be removed. Although the function naming
|
||||
* matches getAllParts, which returns the current part, it also doesn't only
|
||||
* remove direct children like getChildParts. Internally this function uses
|
||||
* getAllParts but the current part is filtered out if returned.
|
||||
*
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of removed parts.
|
||||
*/
|
||||
public function removeAllParts(?callable $fnFilter = null) : int;
|
||||
}
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/IUUEncodedPart.php
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/IUUEncodedPart.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* An interface representing a non-mime uuencoded part.
|
||||
*
|
||||
* Prior to the MIME standard, a plain text email may have included attachments
|
||||
* below it surrounded by 'begin' and 'end' lines and uuencoded data between
|
||||
* them. Those attachments are captured as 'IUUEncodedPart' objects.
|
||||
*
|
||||
* The 'begin' line included a file name and unix file mode. IUUEncodedPart
|
||||
* allows reading/setting those parameters.
|
||||
*
|
||||
* IUUEncodedPart returns a Content-Transfer-Encoding of x-uuencode, a
|
||||
* Content-Type of application-octet-stream, and a Content-Disposition of
|
||||
* 'attachment'. It also expects a mode and filename to initialize it, and
|
||||
* adds 'filename' parts to the Content-Disposition and a 'name' parameter to
|
||||
* Content-Type.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IUUEncodedPart extends IMessagePart
|
||||
{
|
||||
/**
|
||||
* Sets the filename included in the uuencoded 'begin' line.
|
||||
*/
|
||||
public function setFilename(string $filename) : static;
|
||||
|
||||
/**
|
||||
* Returns the file mode included in the uuencoded 'begin' line for this
|
||||
* part.
|
||||
*/
|
||||
public function getUnixFileMode() : ?int;
|
||||
|
||||
/**
|
||||
* Sets the unix file mode for the uuencoded 'begin' line.
|
||||
*/
|
||||
public function setUnixFileMode(int $mode) : static;
|
||||
}
|
||||
253
plugins/vendor/zbateson/mail-mime-parser/src/Message/MessagePart.php
vendored
Normal file
253
plugins/vendor/zbateson/mail-mime-parser/src/Message/MessagePart.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamWrapper;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use SplObjectStorage;
|
||||
use SplObserver;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
use ZBateson\MailMimeParser\Stream\MessagePartStreamDecorator;
|
||||
|
||||
/**
|
||||
* Most basic representation of a single part of an email.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class MessagePart extends ErrorBag implements IMessagePart
|
||||
{
|
||||
/**
|
||||
* @var ?IMimePart parent part
|
||||
*/
|
||||
protected ?IMimePart $parent;
|
||||
|
||||
/**
|
||||
* @var PartStreamContainer holds 'stream' and 'content stream'.
|
||||
*/
|
||||
protected PartStreamContainer $partStreamContainer;
|
||||
|
||||
/**
|
||||
* @var ?string can be used to set an override for content's charset in cases
|
||||
* where a user knows the charset on the content is not what it claims
|
||||
* to be.
|
||||
*/
|
||||
protected ?string $charsetOverride = null;
|
||||
|
||||
/**
|
||||
* @var bool set to true when a user attaches a stream manually, it's
|
||||
* assumed to already be decoded or to have relevant transfer encoding
|
||||
* decorators attached already.
|
||||
*/
|
||||
protected bool $ignoreTransferEncoding = false;
|
||||
|
||||
/**
|
||||
* @var SplObjectStorage attached observers that need to be notified of
|
||||
* modifications to this part.
|
||||
*/
|
||||
protected SplObjectStorage $observers;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
PartStreamContainer $streamContainer,
|
||||
?IMimePart $parent = null
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->partStreamContainer = $streamContainer;
|
||||
$this->parent = $parent;
|
||||
$this->observers = new SplObjectStorage();
|
||||
}
|
||||
|
||||
public function attach(SplObserver $observer) : void
|
||||
{
|
||||
$this->observers->offsetSet($observer);
|
||||
}
|
||||
|
||||
public function detach(SplObserver $observer) : void
|
||||
{
|
||||
$this->observers->offsetUnset($observer);
|
||||
}
|
||||
|
||||
public function notify() : void
|
||||
{
|
||||
foreach ($this->observers as $observer) {
|
||||
$observer->update($this);
|
||||
}
|
||||
if ($this->parent !== null) {
|
||||
$this->parent->notify();
|
||||
}
|
||||
}
|
||||
|
||||
public function getParent() : ?IMimePart
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function hasContent() : bool
|
||||
{
|
||||
return $this->partStreamContainer->hasContent();
|
||||
}
|
||||
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setCharsetOverride(string $charsetOverride, bool $onlyIfNoCharset = false) : static
|
||||
{
|
||||
if (!$onlyIfNoCharset || $this->getCharset() === null) {
|
||||
$this->charsetOverride = $charsetOverride;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentStream(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->hasContent()) {
|
||||
$tr = ($this->ignoreTransferEncoding) ? '' : $this->getContentTransferEncoding();
|
||||
$ch = $this->charsetOverride ?? $this->getCharset();
|
||||
return $this->partStreamContainer->getContentStream(
|
||||
$this,
|
||||
$tr,
|
||||
$ch,
|
||||
$charset
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getBinaryContentStream() : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->hasContent()) {
|
||||
$tr = ($this->ignoreTransferEncoding) ? '' : $this->getContentTransferEncoding();
|
||||
return $this->partStreamContainer->getBinaryContentStream($this, $tr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getBinaryContentResourceHandle() : mixed
|
||||
{
|
||||
$stream = $this->getBinaryContentStream();
|
||||
if ($stream !== null) {
|
||||
return StreamWrapper::getResource($stream);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function saveContent($filenameResourceOrStream) : static
|
||||
{
|
||||
$resourceOrStream = $filenameResourceOrStream;
|
||||
if (\is_string($filenameResourceOrStream)) {
|
||||
$resourceOrStream = \fopen($filenameResourceOrStream, 'w+');
|
||||
}
|
||||
|
||||
$stream = Utils::streamFor($resourceOrStream);
|
||||
Utils::copyToStream($this->getBinaryContentStream(), $stream);
|
||||
|
||||
if (!\is_string($filenameResourceOrStream)
|
||||
&& !($filenameResourceOrStream instanceof StreamInterface)) {
|
||||
// only detach if it wasn't a string or StreamInterface, so the
|
||||
// fopen call can be properly closed if it was
|
||||
$stream->detach();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string
|
||||
{
|
||||
$stream = $this->getContentStream($charset);
|
||||
if ($stream !== null) {
|
||||
return $stream->getContents();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function attachContentStream(StreamInterface $stream, string $streamCharset = MailMimeParser::DEFAULT_CHARSET) : static
|
||||
{
|
||||
$ch = $this->charsetOverride ?? $this->getCharset();
|
||||
if ($ch !== null && $streamCharset !== $ch) {
|
||||
$this->charsetOverride = $streamCharset;
|
||||
}
|
||||
$this->ignoreTransferEncoding = true;
|
||||
$this->partStreamContainer->setContentStream($stream);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function detachContentStream() : static
|
||||
{
|
||||
$this->partStreamContainer->setContentStream(null);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setContent($resource, string $charset = MailMimeParser::DEFAULT_CHARSET) : static
|
||||
{
|
||||
$stream = Utils::streamFor($resource);
|
||||
$this->attachContentStream($stream, $charset);
|
||||
// this->notify() called in attachContentStream
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResourceHandle() : mixed
|
||||
{
|
||||
return StreamWrapper::getResource($this->getStream());
|
||||
}
|
||||
|
||||
public function getStream() : StreamInterface
|
||||
{
|
||||
return $this->partStreamContainer->getStream();
|
||||
}
|
||||
|
||||
public function save($filenameResourceOrStream, string $filemode = 'w+') : static
|
||||
{
|
||||
$resourceOrStream = $filenameResourceOrStream;
|
||||
if (\is_string($filenameResourceOrStream)) {
|
||||
$resourceOrStream = \fopen($filenameResourceOrStream, $filemode);
|
||||
}
|
||||
|
||||
$partStream = $this->getStream();
|
||||
$partStream->rewind();
|
||||
$stream = Utils::streamFor($resourceOrStream);
|
||||
Utils::copyToStream($partStream, $stream);
|
||||
|
||||
if (!\is_string($filenameResourceOrStream)
|
||||
&& !($filenameResourceOrStream instanceof StreamInterface)) {
|
||||
// only detach if it wasn't a string or StreamInterface, so the
|
||||
// fopen call can be properly closed if it was
|
||||
$stream->detach();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->getStream()->getContents();
|
||||
}
|
||||
|
||||
public function getErrorLoggingContextName() : string
|
||||
{
|
||||
$params = '';
|
||||
if (!empty($this->getContentId())) {
|
||||
$params .= ', content-id=' . $this->getContentId();
|
||||
}
|
||||
$params .= ', content-type=' . $this->getContentType();
|
||||
$nsClass = static::class;
|
||||
$class = \substr($nsClass, (\strrpos($nsClass, '\\') ?? -1) + 1);
|
||||
return $class . '(' . \spl_object_id($this) . $params . ')';
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return [
|
||||
$this->partStreamContainer
|
||||
];
|
||||
}
|
||||
}
|
||||
302
plugins/vendor/zbateson/mail-mime-parser/src/Message/MimePart.php
vendored
Normal file
302
plugins/vendor/zbateson/mail-mime-parser/src/Message/MimePart.php
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
use ZBateson\MailMimeParser\Header\ParameterHeader;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* A mime email message part.
|
||||
*
|
||||
* A MIME part may contain any combination of headers, content and children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MimePart extends MultiPart implements IMimePart
|
||||
{
|
||||
/**
|
||||
* @var PartHeaderContainer Container for this part's headers.
|
||||
*/
|
||||
protected PartHeaderContainer $headerContainer;
|
||||
|
||||
public function __construct(
|
||||
?IMimePart $parent = null,
|
||||
?LoggerInterface $logger = null,
|
||||
?PartStreamContainer $streamContainer = null,
|
||||
?PartHeaderContainer $headerContainer = null,
|
||||
?PartChildrenContainer $partChildrenContainer = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$streamContainer ?? $di->get(PartStreamContainer::class),
|
||||
$partChildrenContainer ?? $di->get(PartChildrenContainer::class),
|
||||
$parent
|
||||
);
|
||||
$this->headerContainer = $headerContainer ?? $di->get(PartHeaderContainer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filename for the part if one is defined, or null otherwise.
|
||||
*
|
||||
* Uses the 'filename' parameter of the Content-Disposition header if it
|
||||
* exists, or the 'name' parameter of the 'Content-Type' header if it
|
||||
* doesn't.
|
||||
*
|
||||
* @return string|null the file name of the part or null.
|
||||
*/
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return $this->getHeaderParameter(
|
||||
HeaderConsts::CONTENT_DISPOSITION,
|
||||
'filename',
|
||||
$this->getHeaderParameter(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
'name'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isMultiPart() : bool
|
||||
{
|
||||
// casting to bool, preg_match returns 1 for true
|
||||
return (bool) (\preg_match(
|
||||
'~multipart/.*~i',
|
||||
$this->getContentType()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this part has a defined 'charset' on its Content-Type
|
||||
* header.
|
||||
*
|
||||
* This may result in some false positives if charset is set on a part that
|
||||
* is not plain text which has been seen. If a part is known to be binary,
|
||||
* it's better to use {@see IMessagePart::getBinaryContentStream()} to
|
||||
* avoid issues, or to call {@see IMessagePart::saveContent()} directly if
|
||||
* saving a part's content.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return ($this->getCharset() !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the content, or $default if one is not set.
|
||||
*
|
||||
* Looks at the part's Content-Type header and returns its value if set, or
|
||||
* defaults to 'text/plain'.
|
||||
*
|
||||
* Note that the returned value is converted to lower case, and may not be
|
||||
* identical to calling {@see MimePart::getHeaderValue('Content-Type')} in
|
||||
* some cases.
|
||||
*
|
||||
* @param string $default Optional default value to specify a default other
|
||||
* than text/plain if needed.
|
||||
* @return string the mime type
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string
|
||||
{
|
||||
return \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TYPE, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset of the content, or null if not applicable/defined.
|
||||
*
|
||||
* Looks for a 'charset' parameter under the 'Content-Type' header of this
|
||||
* part and returns it if set, defaulting to 'ISO-8859-1' if the
|
||||
* Content-Type header exists and is of type text/plain or text/html.
|
||||
*
|
||||
* Note that the returned value is also converted to upper case.
|
||||
*
|
||||
* @return string|null the charset
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
$charset = $this->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'charset');
|
||||
if ($charset === null || \strcasecmp($charset, 'binary') === 0) {
|
||||
$contentType = $this->getContentType();
|
||||
if ($contentType === 'text/plain' || $contentType === 'text/html') {
|
||||
return 'ISO-8859-1';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return \strtoupper($charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content's disposition, or returns the value of $default if
|
||||
* not defined.
|
||||
*
|
||||
* Looks at the 'Content-Disposition' header, which should only contain
|
||||
* either 'inline' or 'attachment'. If the header is not one of those
|
||||
* values, $default is returned, which defaults to 'inline' unless passed
|
||||
* something else.
|
||||
*
|
||||
* @param string $default Optional default value if not set or does not
|
||||
* match 'inline' or 'attachment'.
|
||||
* @return string the content disposition
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'inline') : ?string
|
||||
{
|
||||
$value = $this->getHeaderValue(HeaderConsts::CONTENT_DISPOSITION);
|
||||
if ($value === null || !\in_array($value, ['inline', 'attachment'])) {
|
||||
return $default;
|
||||
}
|
||||
return \strtolower($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content transfer encoding used to encode the content on this
|
||||
* part, or the value of $default if not defined.
|
||||
*
|
||||
* Looks up and returns the value of the 'Content-Transfer-Encoding' header
|
||||
* if set, defaulting to '7bit' if an alternate $default param is not
|
||||
* passed.
|
||||
*
|
||||
* The returned value is always lowercase, and header values of 'x-uue',
|
||||
* 'uue' and 'uuencode' will return 'x-uuencode' instead.
|
||||
*
|
||||
* @param string $default Optional default value to return if the header
|
||||
* isn't set.
|
||||
* @return string the content transfer encoding.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = '7bit') : ?string
|
||||
{
|
||||
static $translated = [
|
||||
'x-uue' => 'x-uuencode',
|
||||
'uue' => 'x-uuencode',
|
||||
'uuencode' => 'x-uuencode'
|
||||
];
|
||||
$type = \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TRANSFER_ENCODING, $default));
|
||||
if (isset($translated[$type])) {
|
||||
return $translated[$type];
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part, or null if not defined.
|
||||
*
|
||||
* Looks up and returns the value of the 'Content-ID' header.
|
||||
*
|
||||
* @return string|null the content ID or null if not defined.
|
||||
*/
|
||||
public function getContentId() : ?string
|
||||
{
|
||||
return $this->getHeaderValue(HeaderConsts::CONTENT_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this part's parent is an IMessage, and is the same part
|
||||
* returned by {@see IMessage::getSignaturePart()}.
|
||||
*/
|
||||
public function isSignaturePart() : bool
|
||||
{
|
||||
if ($this->parent === null || !$this->parent instanceof IMessage) {
|
||||
return false;
|
||||
}
|
||||
return $this->parent->getSignaturePart() === $this;
|
||||
}
|
||||
|
||||
public function getHeader(string $name, int $offset = 0) : ?IHeader
|
||||
{
|
||||
return $this->headerContainer->get($name, $offset);
|
||||
}
|
||||
|
||||
public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
|
||||
{
|
||||
return $this->headerContainer->getAs($name, $iHeaderClass, $offset);
|
||||
}
|
||||
|
||||
public function getAllHeaders() : array
|
||||
{
|
||||
return $this->headerContainer->getHeaderObjects();
|
||||
}
|
||||
|
||||
public function getAllHeadersByName(string $name) : array
|
||||
{
|
||||
return $this->headerContainer->getAll($name);
|
||||
}
|
||||
|
||||
public function getRawHeaders() : array
|
||||
{
|
||||
return $this->headerContainer->getHeaders();
|
||||
}
|
||||
|
||||
public function getRawHeaderIterator() : Traversable
|
||||
{
|
||||
return $this->headerContainer->getIterator();
|
||||
}
|
||||
|
||||
public function getHeaderValue(string $name, ?string $defaultValue = null) : ?string
|
||||
{
|
||||
$header = $this->getHeader($name);
|
||||
if ($header !== null) {
|
||||
return $header->getValue() ?: $defaultValue;
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
public function getHeaderParameter(string $header, string $param, ?string $defaultValue = null) : ?string
|
||||
{
|
||||
$obj = $this->getHeader($header);
|
||||
if ($obj && $obj instanceof ParameterHeader) {
|
||||
return $obj->getValueFor($param, $defaultValue);
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
public function setRawHeader(string $name, ?string $value, int $offset = 0) : static
|
||||
{
|
||||
$this->headerContainer->set($name, $value, $offset);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addRawHeader(string $name, string $value) : static
|
||||
{
|
||||
$this->headerContainer->add($name, $value);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeHeader(string $name) : static
|
||||
{
|
||||
$this->headerContainer->removeAll($name);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSingleHeader(string $name, int $offset = 0) : static
|
||||
{
|
||||
$this->headerContainer->remove($name, $offset);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_merge(parent::getErrorBagChildren(), [$this->headerContainer]);
|
||||
}
|
||||
}
|
||||
178
plugins/vendor/zbateson/mail-mime-parser/src/Message/MultiPart.php
vendored
Normal file
178
plugins/vendor/zbateson/mail-mime-parser/src/Message/MultiPart.php
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use AppendIterator;
|
||||
use ArrayIterator;
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RecursiveIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
/**
|
||||
* A message part that contains children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class MultiPart extends MessagePart implements IMultiPart
|
||||
{
|
||||
/**
|
||||
* @var PartChildrenContainer child part container
|
||||
*/
|
||||
protected PartChildrenContainer $partChildrenContainer;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
PartStreamContainer $streamContainer,
|
||||
PartChildrenContainer $partChildrenContainer,
|
||||
?IMimePart $parent = null
|
||||
) {
|
||||
parent::__construct($logger, $streamContainer, $parent);
|
||||
$this->partChildrenContainer = $partChildrenContainer;
|
||||
}
|
||||
|
||||
private function getAllPartsIterator() : AppendIterator
|
||||
{
|
||||
$iter = new AppendIterator();
|
||||
$iter->append(new ArrayIterator([$this]));
|
||||
$iter->append(new RecursiveIteratorIterator($this->partChildrenContainer, RecursiveIteratorIterator::SELF_FIRST));
|
||||
return $iter;
|
||||
}
|
||||
|
||||
private function iteratorFindAt(Iterator $iter, int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
$pos = 0;
|
||||
foreach ($iter as $part) {
|
||||
if (($fnFilter === null || $fnFilter($part))) {
|
||||
if ($index === $pos) {
|
||||
return $part;
|
||||
}
|
||||
++$pos;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPart(int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
return $this->iteratorFindAt(
|
||||
$this->getAllPartsIterator(),
|
||||
$index,
|
||||
$fnFilter
|
||||
);
|
||||
}
|
||||
|
||||
public function getAllParts(?callable $fnFilter = null) : array
|
||||
{
|
||||
$array = \iterator_to_array($this->getAllPartsIterator(), false);
|
||||
if ($fnFilter !== null) {
|
||||
return \array_values(\array_filter($array, $fnFilter));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function getPartCount(?callable $fnFilter = null) : int
|
||||
{
|
||||
return \count($this->getAllParts($fnFilter));
|
||||
}
|
||||
|
||||
public function getChild(int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
return $this->iteratorFindAt(
|
||||
$this->partChildrenContainer,
|
||||
$index,
|
||||
$fnFilter
|
||||
);
|
||||
}
|
||||
|
||||
public function getChildIterator() : RecursiveIterator
|
||||
{
|
||||
return $this->partChildrenContainer;
|
||||
}
|
||||
|
||||
public function getChildParts(?callable $fnFilter = null) : array
|
||||
{
|
||||
$array = \iterator_to_array($this->partChildrenContainer, false);
|
||||
if ($fnFilter !== null) {
|
||||
return \array_values(\array_filter($array, $fnFilter));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function getChildCount(?callable $fnFilter = null) : int
|
||||
{
|
||||
return \count($this->getChildParts($fnFilter));
|
||||
}
|
||||
|
||||
public function getPartByMimeType(string $mimeType, int $index = 0) : ?IMessagePart
|
||||
{
|
||||
return $this->getPart($index, PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getAllPartsByMimeType(string $mimeType) : array
|
||||
{
|
||||
return $this->getAllParts(PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getCountOfPartsByMimeType(string $mimeType) : int
|
||||
{
|
||||
return $this->getPartCount(PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getPartByContentId(string $contentId) : ?IMessagePart
|
||||
{
|
||||
$sanitized = \preg_replace('/^\s*<|>\s*$/', '', $contentId);
|
||||
return $this->getPart(0, function(IMessagePart $part) use ($sanitized) {
|
||||
$cid = $part->getContentId();
|
||||
return ($cid !== null && \strcasecmp($cid, $sanitized) === 0);
|
||||
});
|
||||
}
|
||||
|
||||
public function addChild(MessagePart $part, ?int $position = null) : static
|
||||
{
|
||||
if ($part !== $this) {
|
||||
$part->parent = $this;
|
||||
$this->partChildrenContainer->add($part, $position);
|
||||
$this->notify();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removePart(IMessagePart $part) : ?int
|
||||
{
|
||||
$parent = $part->getParent();
|
||||
if ($this !== $parent && $parent !== null) {
|
||||
return $parent->removePart($part);
|
||||
}
|
||||
|
||||
$position = $this->partChildrenContainer->remove($part);
|
||||
if ($position !== null) {
|
||||
$this->notify();
|
||||
}
|
||||
return $position;
|
||||
}
|
||||
|
||||
public function removeAllParts(?callable $fnFilter = null) : int
|
||||
{
|
||||
$parts = $this->getAllParts($fnFilter);
|
||||
$count = \count($parts);
|
||||
foreach ($parts as $part) {
|
||||
if ($part === $this) {
|
||||
--$count;
|
||||
continue;
|
||||
}
|
||||
$this->removePart($part);
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_merge(parent::getErrorBagChildren(), $this->getChildParts());
|
||||
}
|
||||
}
|
||||
77
plugins/vendor/zbateson/mail-mime-parser/src/Message/NonMimePart.php
vendored
Normal file
77
plugins/vendor/zbateson/mail-mime-parser/src/Message/NonMimePart.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* Represents part of a non-mime message.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class NonMimePart extends MessagePart
|
||||
{
|
||||
/**
|
||||
* Returns true.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text/plain
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ISO-8859-1
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return 'ISO-8859-1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'inline'.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'inline') : ?string
|
||||
{
|
||||
return 'inline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns '7bit'.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = '7bit') : ?string
|
||||
{
|
||||
return '7bit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part.
|
||||
*
|
||||
* NonMimeParts do not have a Content ID, and so this simply returns null.
|
||||
*
|
||||
*/
|
||||
public function getContentId() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
174
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartChildrenContainer.php
vendored
Normal file
174
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartChildrenContainer.php
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* Container of IMessagePart items for a parent IMultiPart.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartChildrenContainer implements ArrayAccess, RecursiveIterator
|
||||
{
|
||||
/**
|
||||
* @var IMessagePart[] array of child parts of the IMultiPart object that is
|
||||
* holding this container.
|
||||
*/
|
||||
protected array $children;
|
||||
|
||||
/**
|
||||
* @var int current key position within $children for iteration.
|
||||
*/
|
||||
protected $position = 0;
|
||||
|
||||
/**
|
||||
* @param IMessagePart[] $children
|
||||
*/
|
||||
public function __construct(array $children = [])
|
||||
{
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current element is an IMultiPart. Note that the
|
||||
* iterator may still be empty.
|
||||
*/
|
||||
public function hasChildren() : bool
|
||||
{
|
||||
return ($this->current() instanceof IMultiPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current element points to an IMultiPart, its child iterator is
|
||||
* returned by calling {@see IMultiPart::getChildIterator()}.
|
||||
*
|
||||
* @return RecursiveIterator<IMessagePart>|null the iterator
|
||||
*/
|
||||
public function getChildren() : ?RecursiveIterator
|
||||
{
|
||||
if ($this->current() instanceof IMultiPart) {
|
||||
return $this->current()->getChildIterator();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IMessagePart
|
||||
*/
|
||||
public function current() : mixed
|
||||
{
|
||||
return $this->offsetGet($this->position);
|
||||
}
|
||||
|
||||
public function key() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function next() : void
|
||||
{
|
||||
++$this->position;
|
||||
}
|
||||
|
||||
public function rewind() : void
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function valid() : bool
|
||||
{
|
||||
return $this->offsetExists($this->position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the passed IMessagePart to the container in the passed position.
|
||||
*
|
||||
* If position is not passed or null, the part is added to the end, as the
|
||||
* last child in the container.
|
||||
*
|
||||
* @param IMessagePart $part The part to add
|
||||
* @param int $position An optional index position (0-based) to add the
|
||||
* child at.
|
||||
*/
|
||||
public function add(IMessagePart $part, $position = null) : static
|
||||
{
|
||||
$index = $position ?? \count($this->children);
|
||||
\array_splice(
|
||||
$this->children,
|
||||
$index,
|
||||
0,
|
||||
[$part]
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the passed part, and returns the integer position it occupied.
|
||||
*
|
||||
* @param IMessagePart $part The part to remove.
|
||||
* @return int the 0-based position it previously occupied.
|
||||
*/
|
||||
public function remove(IMessagePart $part) : ?int
|
||||
{
|
||||
foreach ($this->children as $key => $child) {
|
||||
if ($child === $part) {
|
||||
$this->offsetUnset($key);
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetExists(mixed $offset) : bool
|
||||
{
|
||||
return isset($this->children[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetGet(mixed $offset) : mixed
|
||||
{
|
||||
return $this->offsetExists($offset) ? $this->children[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param IMessagePart $value
|
||||
*/
|
||||
public function offsetSet(mixed $offset, mixed $value) : void
|
||||
{
|
||||
if (!$value instanceof IMessagePart) {
|
||||
throw new InvalidArgumentException(
|
||||
\get_class($value) . ' is not a ZBateson\MailMimeParser\Message\IMessagePart'
|
||||
);
|
||||
}
|
||||
$index = $offset ?? \count($this->children);
|
||||
$this->children[$index] = $value;
|
||||
if ($index < $this->position) {
|
||||
++$this->position;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetUnset($offset) : void
|
||||
{
|
||||
\array_splice($this->children, $offset, 1);
|
||||
if ($this->position >= $offset) {
|
||||
--$this->position;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartFilter.php
vendored
Normal file
114
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartFilter.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* Collection of static methods that return callables for common IMultiPart
|
||||
* child filters.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class PartFilter
|
||||
{
|
||||
/**
|
||||
* Provides an 'attachment' filter used by Message::getAttachmentPart.
|
||||
*
|
||||
* The method filters out the following types of parts:
|
||||
* - text/plain and text/html parts that do not have an 'attachment'
|
||||
* disposition
|
||||
* - any part that returns true for isMultiPart()
|
||||
* - any part that returns true for isSignaturePart()
|
||||
*/
|
||||
public static function fromAttachmentFilter() : callable
|
||||
{
|
||||
return function(IMessagePart $part) {
|
||||
$type = $part->getContentType();
|
||||
$disp = $part->getContentDisposition();
|
||||
if (\in_array($type, ['text/plain', 'text/html']) && $disp !== null && \strcasecmp($disp, 'inline') === 0) {
|
||||
return false;
|
||||
}
|
||||
return !(($part instanceof IMimePart)
|
||||
&& ($part->isMultiPart() || $part->isSignaturePart()));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a filter that keeps parts that contain a header of $name with a
|
||||
* value that matches $value (case insensitive).
|
||||
*
|
||||
* By default signed parts are excluded. Pass FALSE to the third parameter
|
||||
* to include them.
|
||||
*
|
||||
* @param string $name The header name to look up
|
||||
* @param string $value The value to match
|
||||
* @param bool $excludeSignedParts Optional signed parts exclusion (defaults
|
||||
* to true).
|
||||
*/
|
||||
public static function fromHeaderValue(string $name, string $value, bool $excludeSignedParts = true) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($name, $value, $excludeSignedParts) {
|
||||
if ($part instanceof IMimePart) {
|
||||
if ($excludeSignedParts && $part->isSignaturePart()) {
|
||||
return false;
|
||||
}
|
||||
return (\strcasecmp($part->getHeaderValue($name, ''), $value) === 0);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes only parts that match the passed $mimeType in the return value
|
||||
* of a call to 'getContentType()'.
|
||||
*
|
||||
* @param string $mimeType Mime type of parts to find.
|
||||
*/
|
||||
public static function fromContentType(string $mimeType) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($mimeType) {
|
||||
return \strcasecmp($part->getContentType() ?: '', $mimeType) === 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parts matching $mimeType that do not have a Content-Disposition
|
||||
* set to 'attachment'.
|
||||
*
|
||||
* @param string $mimeType Mime type of parts to find.
|
||||
*/
|
||||
public static function fromInlineContentType(string $mimeType) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($mimeType) {
|
||||
$disp = $part->getContentDisposition();
|
||||
return (\strcasecmp($part->getContentType() ?: '', $mimeType) === 0) && ($disp === null
|
||||
|| \strcasecmp($disp, 'attachment') !== 0);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds parts with the passed disposition (matching against
|
||||
* IMessagePart::getContentDisposition()), optionally including
|
||||
* multipart parts and signed parts.
|
||||
*
|
||||
* @param string $disposition The disposition to find.
|
||||
* @param bool $includeMultipart Optionally include multipart parts by
|
||||
* passing true (defaults to false).
|
||||
* @param bool $includeSignedParts Optionally include signed parts (defaults
|
||||
* to false).
|
||||
*/
|
||||
public static function fromDisposition(string $disposition, bool $includeMultipart = false, bool $includeSignedParts = false) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($disposition, $includeMultipart, $includeSignedParts) {
|
||||
if (($part instanceof IMimePart) && ((!$includeMultipart && $part->isMultiPart()) || (!$includeSignedParts && $part->isSignaturePart()))) {
|
||||
return false;
|
||||
}
|
||||
$disp = $part->getContentDisposition();
|
||||
return ($disp !== null && \strcasecmp($disp, $disposition) === 0);
|
||||
};
|
||||
}
|
||||
}
|
||||
325
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartHeaderContainer.php
vendored
Normal file
325
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartHeaderContainer.php
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Header\HeaderFactory;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
|
||||
/**
|
||||
* Maintains a collection of headers for a part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartHeaderContainer extends ErrorBag implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var HeaderFactory the HeaderFactory object used for created headers
|
||||
*/
|
||||
protected $headerFactory;
|
||||
|
||||
/**
|
||||
* @var string[][] Each element in the array is an array with its first
|
||||
* element set to the header's name, and the second its value.
|
||||
*/
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* @var \ZBateson\MailMimeParser\Header\IHeader[] Each element is an IHeader
|
||||
* representing the header at the same index in the $headers array. If
|
||||
* an IHeader has not been constructed for the header at that index,
|
||||
* the element would be set to null.
|
||||
*/
|
||||
private $headerObjects = [];
|
||||
|
||||
/**
|
||||
* @var array Maps header names by their "normalized" (lower-cased,
|
||||
* non-alphanumeric characters stripped) name to an array of indexes in
|
||||
* the $headers array. For example:
|
||||
* $headerMap['contenttype'] = [ 1, 4 ]
|
||||
* would indicate that the headers in $headers[1] and $headers[4] are
|
||||
* both headers with the name 'Content-Type' or 'contENTtype'.
|
||||
*/
|
||||
private $headerMap = [];
|
||||
|
||||
/**
|
||||
* @var int the next index to use for $headers and $headerObjects.
|
||||
*/
|
||||
private $nextIndex = 0;
|
||||
|
||||
/**
|
||||
* Pass a PartHeaderContainer as the second parameter. This is useful when
|
||||
* creating a new MimePart with this PartHeaderContainer and the original
|
||||
* container is needed for parsing and changes to the header in the part
|
||||
* should not affect parsing.
|
||||
*
|
||||
* @param PartHeaderContainer $cloneSource the original container to clone
|
||||
* from
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderFactory $headerFactory,
|
||||
?PartHeaderContainer $cloneSource = null
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->headerFactory = $headerFactory;
|
||||
if ($cloneSource !== null) {
|
||||
$this->headers = $cloneSource->headers;
|
||||
$this->headerObjects = $cloneSource->headerObjects;
|
||||
$this->headerMap = $cloneSource->headerMap;
|
||||
$this->nextIndex = $cloneSource->nextIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed header exists in this collection.
|
||||
*/
|
||||
public function exists(string $name, int $offset = 0) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
return isset($this->headerMap[$s][$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of header indexes with names that more closely match
|
||||
* the passed $name if available: for instance if there are two headers in
|
||||
* an email, "Content-Type" and "ContentType", and the query is for a header
|
||||
* with the name "Content-Type", only headers that match exactly
|
||||
* "Content-Type" would be returned.
|
||||
*
|
||||
* @return int[]|null
|
||||
*/
|
||||
private function getAllWithOriginalHeaderNameIfSet(string $name) : ?array
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (isset($this->headerMap[$s])) {
|
||||
$self = $this;
|
||||
$filtered = \array_filter($this->headerMap[$s], function($h) use ($name, $self) {
|
||||
return (\strcasecmp($self->headers[$h][0], $name) === 0);
|
||||
});
|
||||
return (!empty($filtered)) ? $filtered : $this->headerMap[$s];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, or null
|
||||
* if none exist.
|
||||
*
|
||||
* An optional offset can be provided, which defaults to the first header in
|
||||
* the collection when more than one header with the same name exists.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*/
|
||||
public function get(string $name, int $offset = 0) : ?IHeader
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a) && isset($a[$offset])) {
|
||||
return $this->getByIndex($a[$offset]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, or null
|
||||
* if none exist, using the passed $iHeaderClass to construct it.
|
||||
*
|
||||
* An optional offset can be provided, which defaults to the first header in
|
||||
* the collection when more than one header with the same name exists.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*/
|
||||
public function getAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a) && isset($a[$offset])) {
|
||||
return $this->getByIndexAs($a[$offset], $iHeaderClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all headers with the passed name.
|
||||
*
|
||||
* @return IHeader[]
|
||||
*/
|
||||
public function getAll(string $name) : array
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a)) {
|
||||
$self = $this;
|
||||
return \array_map(function($index) use ($self) {
|
||||
return $self->getByIndex($index);
|
||||
}, $a);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header in the headers array at the passed 0-based integer
|
||||
* index or null if one doesn't exist.
|
||||
*/
|
||||
private function getByIndex(int $index) : ?IHeader
|
||||
{
|
||||
if (!isset($this->headers[$index])) {
|
||||
return null;
|
||||
}
|
||||
if ($this->headerObjects[$index] === null) {
|
||||
$this->headerObjects[$index] = $this->headerFactory->newInstance(
|
||||
$this->headers[$index][0],
|
||||
$this->headers[$index][1]
|
||||
);
|
||||
}
|
||||
return $this->headerObjects[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header in the headers array at the passed 0-based integer
|
||||
* index or null if one doesn't exist, using the passed $iHeaderClass to
|
||||
* construct it.
|
||||
*/
|
||||
private function getByIndexAs(int $index, string $iHeaderClass) : ?IHeader
|
||||
{
|
||||
if (!isset($this->headers[$index])) {
|
||||
return null;
|
||||
}
|
||||
if ($this->headerObjects[$index] !== null && \get_class($this->headerObjects[$index]) === $iHeaderClass) {
|
||||
return $this->headerObjects[$index];
|
||||
}
|
||||
return $this->headerFactory->newInstanceOf(
|
||||
$this->headers[$index][0],
|
||||
$this->headers[$index][1],
|
||||
$iHeaderClass
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the header from the collection with the passed name. Defaults to
|
||||
* removing the first instance of the header for a collection that contains
|
||||
* more than one with the same passed name.
|
||||
*
|
||||
* @return bool true if a header was found and removed.
|
||||
*/
|
||||
public function remove(string $name, int $offset = 0) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (isset($this->headerMap[$s][$offset])) {
|
||||
$index = $this->headerMap[$s][$offset];
|
||||
\array_splice($this->headerMap[$s], $offset, 1);
|
||||
unset($this->headers[$index], $this->headerObjects[$index]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all headers that match the passed name.
|
||||
*
|
||||
* @return bool true if one or more headers were removed.
|
||||
*/
|
||||
public function removeAll(string $name) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (!empty($this->headerMap[$s])) {
|
||||
foreach ($this->headerMap[$s] as $i) {
|
||||
unset($this->headers[$i], $this->headerObjects[$i]);
|
||||
}
|
||||
$this->headerMap[$s] = [];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the header to the collection.
|
||||
*/
|
||||
public function add(string $name, string $value) : static
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
$this->headers[$this->nextIndex] = [$name, $value];
|
||||
$this->headerObjects[$this->nextIndex] = null;
|
||||
if (!isset($this->headerMap[$s])) {
|
||||
$this->headerMap[$s] = [];
|
||||
}
|
||||
$this->headerMap[$s][] = $this->nextIndex;
|
||||
$this->nextIndex++;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a header exists with the passed name, and at the passed offset if more
|
||||
* than one exists, its value is updated.
|
||||
*
|
||||
* If a header with the passed name doesn't exist at the passed offset, it
|
||||
* is created at the next available offset (offset is ignored when adding).
|
||||
*/
|
||||
public function set(string $name, string $value, int $offset = 0) : static
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (!isset($this->headerMap[$s][$offset])) {
|
||||
$this->add($name, $value);
|
||||
return $this;
|
||||
}
|
||||
$i = $this->headerMap[$s][$offset];
|
||||
$this->headers[$i] = [$name, $value];
|
||||
$this->headerObjects[$i] = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of IHeader objects representing all headers in this
|
||||
* collection.
|
||||
*
|
||||
* @return IHeader[]
|
||||
*/
|
||||
public function getHeaderObjects() : array
|
||||
{
|
||||
return \array_filter(\array_map([$this, 'getByIndex'], \array_keys($this->headers)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of headers in this collection. Each returned element in
|
||||
* the array is an array with the first element set to the name, and the
|
||||
* second its value:
|
||||
*
|
||||
* [
|
||||
* [ 'Header-Name', 'Header Value' ],
|
||||
* [ 'Second-Header-Name', 'Second-Header-Value' ],
|
||||
* // etc...
|
||||
* ]
|
||||
*
|
||||
* @return string[][]
|
||||
*/
|
||||
public function getHeaders() : array
|
||||
{
|
||||
return \array_values(\array_filter($this->headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the headers in this collection. Each returned
|
||||
* element is an array with its first element set to the header's name, and
|
||||
* the second to its value:
|
||||
*
|
||||
* [ 'Header-Name', 'Header Value' ]
|
||||
*
|
||||
* return Traversable<array<string>>
|
||||
*/
|
||||
public function getIterator() : Traversable
|
||||
{
|
||||
return new ArrayIterator($this->getHeaders());
|
||||
}
|
||||
|
||||
public function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_values(\array_filter($this->headerObjects));
|
||||
}
|
||||
}
|
||||
335
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartStreamContainer.php
vendored
Normal file
335
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartStreamContainer.php
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use GuzzleHttp\Psr7\CachingStream;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Stream\MessagePartStreamDecorator;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
use ZBateson\MbWrapper\UnsupportedCharsetException;
|
||||
|
||||
/**
|
||||
* Holds the stream and content stream objects for a part.
|
||||
*
|
||||
* Note that streams are not explicitly closed or detached on destruction of the
|
||||
* PartSreamContainer by design: the passed StreamInterfaces will be closed on
|
||||
* their destruction when no references to them remain, which is useful when the
|
||||
* streams are passed around.
|
||||
*
|
||||
* In addition, all the streams passed to PartStreamContainer should be wrapping
|
||||
* a ZBateson\StreamDecorators\NonClosingStream unless attached to a part by a
|
||||
* user, this is because MMP uses a single seekable stream for content and wraps
|
||||
* it in ZBateson\StreamDecorators\SeekingLimitStream objects for each part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartStreamContainer extends ErrorBag
|
||||
{
|
||||
/**
|
||||
* @var MbWrapper to test charsets and see if they're supported.
|
||||
*/
|
||||
protected MbWrapper $mbWrapper;
|
||||
|
||||
/**
|
||||
* @var bool if false, reading from a content stream with an unsupported
|
||||
* charset will be tried with the default charset, otherwise the stream
|
||||
* created with the unsupported charset, and an exception will be
|
||||
* thrown when read from.
|
||||
*/
|
||||
protected bool $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
|
||||
/**
|
||||
* @var StreamFactory used to apply psr7 stream decorators to the
|
||||
* attached StreamInterface based on encoding.
|
||||
*/
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
/**
|
||||
* @var MessagePartStreamDecorator stream containing the part's headers,
|
||||
* content and children wrapped in a MessagePartStreamDecorator
|
||||
*/
|
||||
protected MessagePartStreamDecorator $stream;
|
||||
|
||||
/**
|
||||
* @var StreamInterface a stream containing this part's content
|
||||
*/
|
||||
protected ?StreamInterface $contentStream = null;
|
||||
|
||||
/**
|
||||
* @var StreamInterface the content stream after attaching transfer encoding
|
||||
* streams to $contentStream.
|
||||
*/
|
||||
protected ?StreamInterface $decodedStream = null;
|
||||
|
||||
/**
|
||||
* @var StreamInterface attached charset stream to $decodedStream
|
||||
*/
|
||||
protected ?StreamInterface $charsetStream = null;
|
||||
|
||||
/**
|
||||
* @var bool true if the stream should be detached when this container is
|
||||
* destroyed.
|
||||
*/
|
||||
protected bool $detachParsedStream = false;
|
||||
|
||||
/**
|
||||
* @var array<string, null> map of the active encoding filter on the current handle.
|
||||
*/
|
||||
private array $encoding = [
|
||||
'type' => null,
|
||||
'filter' => null
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string, null> map of the active charset filter on the current handle.
|
||||
*/
|
||||
private array $charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
MbWrapper $mbWrapper,
|
||||
bool $throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->mbWrapper = $mbWrapper;
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets = $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the part's stream containing the part's headers, content, and
|
||||
* children.
|
||||
*/
|
||||
public function setStream(MessagePartStreamDecorator $stream) : static
|
||||
{
|
||||
$this->stream = $stream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part's stream containing the part's headers, content, and
|
||||
* children.
|
||||
*/
|
||||
public function getStream() : MessagePartStreamDecorator
|
||||
{
|
||||
// error out if called before setStream, getStream should never return
|
||||
// null.
|
||||
$this->stream->rewind();
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there's a content stream associated with the part.
|
||||
*/
|
||||
public function hasContent() : bool
|
||||
{
|
||||
return ($this->contentStream !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the passed stream as the content portion of this
|
||||
* StreamContainer.
|
||||
*
|
||||
* The content stream would represent the content portion of $this->stream.
|
||||
*
|
||||
* If the content is overridden, $this->stream should point to a dynamic
|
||||
* {@see ZBateson\Stream\MessagePartStream} that dynamically creates the
|
||||
* RFC822 formatted message based on the IMessagePart this
|
||||
* PartStreamContainer belongs to.
|
||||
*
|
||||
* setContentStream can be called with 'null' to indicate the IMessagePart
|
||||
* does not contain any content.
|
||||
*/
|
||||
public function setContentStream(?StreamInterface $contentStream = null) : static
|
||||
{
|
||||
$this->contentStream = $contentStream;
|
||||
$this->decodedStream = null;
|
||||
$this->charsetStream = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the attached stream filter used for decoding the content
|
||||
* on the current handle is different from the one passed as an argument.
|
||||
*/
|
||||
private function isTransferEncodingFilterChanged(?string $transferEncoding) : bool
|
||||
{
|
||||
return ($transferEncoding !== $this->encoding['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the attached stream filter used for charset conversion on
|
||||
* the current handle is different from the one needed based on the passed
|
||||
* arguments.
|
||||
*
|
||||
*/
|
||||
private function isCharsetFilterChanged(string $fromCharset, string $toCharset) : bool
|
||||
{
|
||||
return ($fromCharset !== $this->charset['from']
|
||||
|| $toCharset !== $this->charset['to']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a decoding filter to the attached content handle, for the passed
|
||||
* $transferEncoding.
|
||||
*/
|
||||
protected function attachTransferEncodingFilter(?string $transferEncoding) : static
|
||||
{
|
||||
if ($this->decodedStream !== null) {
|
||||
$this->encoding['type'] = $transferEncoding;
|
||||
$this->decodedStream = new CachingStream($this->streamFactory->getTransferEncodingDecoratedStream(
|
||||
$this->decodedStream,
|
||||
$transferEncoding
|
||||
));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a charset conversion filter to the attached content handle, for
|
||||
* the passed arguments.
|
||||
*
|
||||
* @param string $fromCharset the character set the content is encoded in
|
||||
* @param string $toCharset the target encoding to return
|
||||
*/
|
||||
protected function attachCharsetFilter(string $fromCharset, string $toCharset) : static
|
||||
{
|
||||
if ($this->charsetStream !== null) {
|
||||
if (!$this->throwExceptionReadingPartContentFromUnsupportedCharsets) {
|
||||
try {
|
||||
$this->mbWrapper->convert('t', $fromCharset, $toCharset);
|
||||
$this->charsetStream = new CachingStream($this->streamFactory->newCharsetStream(
|
||||
$this->charsetStream,
|
||||
$fromCharset,
|
||||
$toCharset
|
||||
));
|
||||
} catch (UnsupportedCharsetException $ex) {
|
||||
$this->addError('Unsupported character set found', LogLevel::ERROR, $ex);
|
||||
$this->charsetStream = new CachingStream($this->charsetStream);
|
||||
}
|
||||
} else {
|
||||
$this->charsetStream = new CachingStream($this->streamFactory->newCharsetStream(
|
||||
$this->charsetStream,
|
||||
$fromCharset,
|
||||
$toCharset
|
||||
));
|
||||
}
|
||||
$this->charsetStream->rewind();
|
||||
$this->charset['from'] = $fromCharset;
|
||||
$this->charset['to'] = $toCharset;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets just the charset stream, and rewinds the decodedStream.
|
||||
*/
|
||||
private function resetCharsetStream() : static
|
||||
{
|
||||
$this->charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->decodedStream->rewind();
|
||||
$this->charsetStream = $this->decodedStream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets cached encoding and charset streams, and rewinds the stream.
|
||||
*/
|
||||
public function reset() : static
|
||||
{
|
||||
$this->encoding = [
|
||||
'type' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->contentStream->rewind();
|
||||
$this->decodedStream = $this->contentStream;
|
||||
$this->charsetStream = $this->contentStream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what transfer-encoding decoder stream and charset conversion
|
||||
* stream are currently attached on the underlying contentStream, and resets
|
||||
* them if the requested arguments differ from the currently assigned ones.
|
||||
*
|
||||
* @param IMessagePart $part the part the stream belongs to
|
||||
* @param string $transferEncoding the transfer encoding
|
||||
* @param string $fromCharset the character set the content is encoded in
|
||||
* @param string $toCharset the target encoding to return
|
||||
*/
|
||||
public function getContentStream(
|
||||
IMessagePart $part,
|
||||
?string $transferEncoding,
|
||||
?string $fromCharset,
|
||||
?string $toCharset
|
||||
) : ?MessagePartStreamDecorator {
|
||||
if ($this->contentStream === null) {
|
||||
return null;
|
||||
}
|
||||
if (empty($fromCharset) || empty($toCharset)) {
|
||||
return $this->getBinaryContentStream($part, $transferEncoding);
|
||||
}
|
||||
if ($this->charsetStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)
|
||||
|| $this->isCharsetFilterChanged($fromCharset, $toCharset)) {
|
||||
if ($this->charsetStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)) {
|
||||
$this->reset();
|
||||
$this->attachTransferEncodingFilter($transferEncoding);
|
||||
}
|
||||
$this->resetCharsetStream();
|
||||
$this->attachCharsetFilter($fromCharset, $toCharset);
|
||||
}
|
||||
$this->charsetStream->rewind();
|
||||
return $this->streamFactory->newDecoratedMessagePartStream(
|
||||
$part,
|
||||
$this->charsetStream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what transfer-encoding decoder stream is attached on the
|
||||
* underlying stream, and resets it if the requested arguments differ.
|
||||
*/
|
||||
public function getBinaryContentStream(IMessagePart $part, ?string $transferEncoding = null) : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->contentStream === null) {
|
||||
return null;
|
||||
}
|
||||
if ($this->decodedStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)) {
|
||||
$this->reset();
|
||||
$this->attachTransferEncodingFilter($transferEncoding);
|
||||
}
|
||||
$this->decodedStream->rewind();
|
||||
return $this->streamFactory->newDecoratedMessagePartStream($part, $this->decodedStream);
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
120
plugins/vendor/zbateson/mail-mime-parser/src/Message/UUEncodedPart.php
vendored
Normal file
120
plugins/vendor/zbateson/mail-mime-parser/src/Message/UUEncodedPart.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Implementation of a non-mime message's uuencoded attachment part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class UUEncodedPart extends NonMimePart implements IUUEncodedPart
|
||||
{
|
||||
/**
|
||||
* @var int the unix file permission
|
||||
*/
|
||||
protected ?int $mode = null;
|
||||
|
||||
/**
|
||||
* @var string the name of the file in the uuencoding 'header'.
|
||||
*/
|
||||
protected ?string $filename = null;
|
||||
|
||||
public function __construct(
|
||||
?int $mode = null,
|
||||
?string $filename = null,
|
||||
?IMimePart $parent = null,
|
||||
?LoggerInterface $logger = null,
|
||||
?PartStreamContainer $streamContainer = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$streamContainer ?? $di->get(PartStreamContainer::class),
|
||||
$parent
|
||||
);
|
||||
$this->mode = $mode;
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename included in the uuencoded 'begin' line for this
|
||||
* part.
|
||||
*/
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function setFilename(string $filename) : static
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*
|
||||
* Although the part may be plain text, there is no reliable way of
|
||||
* determining its type since uuencoded 'begin' lines only include a file
|
||||
* name and no mime type. The file name's extension may be a hint.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'application/octet-stream'.
|
||||
*/
|
||||
public function getContentType(string $default = 'application/octet-stream') : ?string
|
||||
{
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'attachment'.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'attachment') : ?string
|
||||
{
|
||||
return 'attachment';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'x-uuencode'.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = 'x-uuencode') : ?string
|
||||
{
|
||||
return 'x-uuencode';
|
||||
}
|
||||
|
||||
public function getUnixFileMode() : ?int
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
|
||||
public function setUnixFileMode(int $mode) : static
|
||||
{
|
||||
$this->mode = $mode;
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user