mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2025-01-15 08:11:14 +01:00
577 lines
16 KiB
PHP
577 lines
16 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* @see https://github.com/laminas/laminas-mail for the canonical source repository
|
||
|
* @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
|
||
|
* @license https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
|
||
|
*/
|
||
|
|
||
|
namespace Laminas\Mail;
|
||
|
|
||
|
use Laminas\Mail\Header\ContentType;
|
||
|
use Laminas\Mail\Header\Sender;
|
||
|
use Laminas\Mime;
|
||
|
use Traversable;
|
||
|
|
||
|
class Message
|
||
|
{
|
||
|
/**
|
||
|
* Content of the message
|
||
|
*
|
||
|
* @var string|object|Mime\Message
|
||
|
*/
|
||
|
protected $body;
|
||
|
|
||
|
/**
|
||
|
* @var Headers
|
||
|
*/
|
||
|
protected $headers;
|
||
|
|
||
|
/**
|
||
|
* Message encoding
|
||
|
*
|
||
|
* Used to determine whether or not to encode headers; defaults to ASCII.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
protected $encoding = 'ASCII';
|
||
|
|
||
|
/**
|
||
|
* Is the message valid?
|
||
|
*
|
||
|
* If we don't any From addresses, we're invalid, according to RFC2822.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isValid()
|
||
|
{
|
||
|
$from = $this->getFrom();
|
||
|
if (! $from instanceof AddressList) {
|
||
|
return false;
|
||
|
}
|
||
|
return (bool) count($from);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the message encoding
|
||
|
*
|
||
|
* @param string $encoding
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setEncoding($encoding)
|
||
|
{
|
||
|
$this->encoding = $encoding;
|
||
|
$this->getHeaders()->setEncoding($encoding);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the message encoding
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getEncoding()
|
||
|
{
|
||
|
return $this->encoding;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Compose headers
|
||
|
*
|
||
|
* @param Headers $headers
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setHeaders(Headers $headers)
|
||
|
{
|
||
|
$this->headers = $headers;
|
||
|
$headers->setEncoding($this->getEncoding());
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Access headers collection
|
||
|
*
|
||
|
* Lazy-loads if not already attached.
|
||
|
*
|
||
|
* @return Headers
|
||
|
*/
|
||
|
public function getHeaders()
|
||
|
{
|
||
|
if (null === $this->headers) {
|
||
|
$this->setHeaders(new Headers());
|
||
|
$date = Header\Date::fromString('Date: ' . date('r'));
|
||
|
$this->headers->addHeader($date);
|
||
|
}
|
||
|
return $this->headers;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set (overwrite) From addresses
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setFrom($emailOrAddressList, $name = null)
|
||
|
{
|
||
|
$this->clearHeaderByName('from');
|
||
|
return $this->addFrom($emailOrAddressList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a "From" address
|
||
|
*
|
||
|
* @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function addFrom($emailOrAddressOrList, $name = null)
|
||
|
{
|
||
|
$addressList = $this->getFrom();
|
||
|
$this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve list of From senders
|
||
|
*
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
public function getFrom()
|
||
|
{
|
||
|
return $this->getAddressListFromHeader('from', __NAMESPACE__ . '\Header\From');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Overwrite the address list in the To recipients
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
|
||
|
* @param null|string $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setTo($emailOrAddressList, $name = null)
|
||
|
{
|
||
|
$this->clearHeaderByName('to');
|
||
|
return $this->addTo($emailOrAddressList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add one or more addresses to the To recipients
|
||
|
*
|
||
|
* Appends to the list.
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param null|string $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function addTo($emailOrAddressOrList, $name = null)
|
||
|
{
|
||
|
$addressList = $this->getTo();
|
||
|
$this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Access the address list of the To header
|
||
|
*
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
public function getTo()
|
||
|
{
|
||
|
return $this->getAddressListFromHeader('to', __NAMESPACE__ . '\Header\To');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set (overwrite) CC addresses
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setCc($emailOrAddressList, $name = null)
|
||
|
{
|
||
|
$this->clearHeaderByName('cc');
|
||
|
return $this->addCc($emailOrAddressList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a "Cc" address
|
||
|
*
|
||
|
* @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function addCc($emailOrAddressOrList, $name = null)
|
||
|
{
|
||
|
$addressList = $this->getCc();
|
||
|
$this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve list of CC recipients
|
||
|
*
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
public function getCc()
|
||
|
{
|
||
|
return $this->getAddressListFromHeader('cc', __NAMESPACE__ . '\Header\Cc');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set (overwrite) BCC addresses
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setBcc($emailOrAddressList, $name = null)
|
||
|
{
|
||
|
$this->clearHeaderByName('bcc');
|
||
|
return $this->addBcc($emailOrAddressList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a "Bcc" address
|
||
|
*
|
||
|
* @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param string|null $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function addBcc($emailOrAddressOrList, $name = null)
|
||
|
{
|
||
|
$addressList = $this->getBcc();
|
||
|
$this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve list of BCC recipients
|
||
|
*
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
public function getBcc()
|
||
|
{
|
||
|
return $this->getAddressListFromHeader('bcc', __NAMESPACE__ . '\Header\Bcc');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Overwrite the address list in the Reply-To recipients
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
|
||
|
* @param null|string $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setReplyTo($emailOrAddressList, $name = null)
|
||
|
{
|
||
|
$this->clearHeaderByName('reply-to');
|
||
|
return $this->addReplyTo($emailOrAddressList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add one or more addresses to the Reply-To recipients
|
||
|
*
|
||
|
* Appends to the list.
|
||
|
*
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param null|string $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function addReplyTo($emailOrAddressOrList, $name = null)
|
||
|
{
|
||
|
$addressList = $this->getReplyTo();
|
||
|
$this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Access the address list of the Reply-To header
|
||
|
*
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
public function getReplyTo()
|
||
|
{
|
||
|
return $this->getAddressListFromHeader('reply-to', __NAMESPACE__ . '\Header\ReplyTo');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* setSender
|
||
|
*
|
||
|
* @param mixed $emailOrAddress
|
||
|
* @param mixed $name
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setSender($emailOrAddress, $name = null)
|
||
|
{
|
||
|
/** @var Sender $header */
|
||
|
$header = $this->getHeaderByName('sender', __NAMESPACE__ . '\Header\Sender');
|
||
|
$header->setAddress($emailOrAddress, $name);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve the sender address, if any
|
||
|
*
|
||
|
* @return null|Address\AddressInterface
|
||
|
*/
|
||
|
public function getSender()
|
||
|
{
|
||
|
$headers = $this->getHeaders();
|
||
|
if (! $headers->has('sender')) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/** @var Sender $header */
|
||
|
$header = $this->getHeaderByName('sender', __NAMESPACE__ . '\Header\Sender');
|
||
|
return $header->getAddress();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the message subject header value
|
||
|
*
|
||
|
* @param string $subject
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setSubject($subject)
|
||
|
{
|
||
|
$headers = $this->getHeaders();
|
||
|
if (! $headers->has('subject')) {
|
||
|
$header = new Header\Subject();
|
||
|
$headers->addHeader($header);
|
||
|
} else {
|
||
|
$header = $headers->get('subject');
|
||
|
}
|
||
|
$header->setSubject($subject);
|
||
|
$header->setEncoding($this->getEncoding());
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the message subject header value
|
||
|
*
|
||
|
* @return null|string
|
||
|
*/
|
||
|
public function getSubject()
|
||
|
{
|
||
|
$headers = $this->getHeaders();
|
||
|
if (! $headers->has('subject')) {
|
||
|
return;
|
||
|
}
|
||
|
$header = $headers->get('subject');
|
||
|
return $header->getFieldValue();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the message body
|
||
|
*
|
||
|
* @param null|string|\Laminas\Mime\Message|object $body
|
||
|
* @throws Exception\InvalidArgumentException
|
||
|
* @return Message
|
||
|
*/
|
||
|
public function setBody($body)
|
||
|
{
|
||
|
if (! is_string($body) && $body !== null) {
|
||
|
if (! is_object($body)) {
|
||
|
throw new Exception\InvalidArgumentException(sprintf(
|
||
|
'%s expects a string or object argument; received "%s"',
|
||
|
__METHOD__,
|
||
|
gettype($body)
|
||
|
));
|
||
|
}
|
||
|
if (! $body instanceof Mime\Message) {
|
||
|
if (! method_exists($body, '__toString')) {
|
||
|
throw new Exception\InvalidArgumentException(sprintf(
|
||
|
'%s expects object arguments of type %s or implementing __toString();'
|
||
|
. ' object of type "%s" received',
|
||
|
__METHOD__,
|
||
|
Mime\Message::class,
|
||
|
get_class($body)
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$this->body = $body;
|
||
|
|
||
|
if (! $this->body instanceof Mime\Message) {
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
// Get headers, and set Mime-Version header
|
||
|
$headers = $this->getHeaders();
|
||
|
$this->getHeaderByName('mime-version', __NAMESPACE__ . '\Header\MimeVersion');
|
||
|
|
||
|
// Multipart content headers
|
||
|
if ($this->body->isMultiPart()) {
|
||
|
$mime = $this->body->getMime();
|
||
|
|
||
|
/** @var ContentType $header */
|
||
|
$header = $this->getHeaderByName('content-type', __NAMESPACE__ . '\Header\ContentType');
|
||
|
$header->setType('multipart/mixed');
|
||
|
$header->addParameter('boundary', $mime->boundary());
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
// MIME single part headers
|
||
|
$parts = $this->body->getParts();
|
||
|
if (! empty($parts)) {
|
||
|
$part = array_shift($parts);
|
||
|
$headers->addHeaders($part->getHeadersArray("\r\n"));
|
||
|
}
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the currently set message body
|
||
|
*
|
||
|
* @return object|string|Mime\Message
|
||
|
*/
|
||
|
public function getBody()
|
||
|
{
|
||
|
return $this->body;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the string-serialized message body text
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getBodyText()
|
||
|
{
|
||
|
if ($this->body instanceof Mime\Message) {
|
||
|
return $this->body->generateMessage(Headers::EOL);
|
||
|
}
|
||
|
|
||
|
return (string) $this->body;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve a header by name
|
||
|
*
|
||
|
* If not found, instantiates one based on $headerClass.
|
||
|
*
|
||
|
* @param string $headerName
|
||
|
* @param string $headerClass
|
||
|
* @return Header\HeaderInterface|\ArrayIterator header instance or collection of headers
|
||
|
*/
|
||
|
protected function getHeaderByName($headerName, $headerClass)
|
||
|
{
|
||
|
$headers = $this->getHeaders();
|
||
|
if ($headers->has($headerName)) {
|
||
|
$header = $headers->get($headerName);
|
||
|
} else {
|
||
|
$header = new $headerClass();
|
||
|
$headers->addHeader($header);
|
||
|
}
|
||
|
return $header;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear a header by name
|
||
|
*
|
||
|
* @param string $headerName
|
||
|
*/
|
||
|
protected function clearHeaderByName($headerName)
|
||
|
{
|
||
|
$this->getHeaders()->removeHeader($headerName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve the AddressList from a named header
|
||
|
*
|
||
|
* Used with To, From, Cc, Bcc, and ReplyTo headers. If the header does not
|
||
|
* exist, instantiates it.
|
||
|
*
|
||
|
* @param string $headerName
|
||
|
* @param string $headerClass
|
||
|
* @throws Exception\DomainException
|
||
|
* @return AddressList
|
||
|
*/
|
||
|
protected function getAddressListFromHeader($headerName, $headerClass)
|
||
|
{
|
||
|
$header = $this->getHeaderByName($headerName, $headerClass);
|
||
|
if (! $header instanceof Header\AbstractAddressList) {
|
||
|
throw new Exception\DomainException(sprintf(
|
||
|
'Cannot grab address list from header of type "%s"; not an AbstractAddressList implementation',
|
||
|
get_class($header)
|
||
|
));
|
||
|
}
|
||
|
return $header->getAddressList();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Update an address list
|
||
|
*
|
||
|
* Proxied to this from addFrom, addTo, addCc, addBcc, and addReplyTo.
|
||
|
*
|
||
|
* @param AddressList $addressList
|
||
|
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
|
||
|
* @param null|string $name
|
||
|
* @param string $callingMethod
|
||
|
* @throws Exception\InvalidArgumentException
|
||
|
*/
|
||
|
protected function updateAddressList(AddressList $addressList, $emailOrAddressOrList, $name, $callingMethod)
|
||
|
{
|
||
|
if ($emailOrAddressOrList instanceof Traversable) {
|
||
|
foreach ($emailOrAddressOrList as $address) {
|
||
|
$addressList->add($address);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
if (is_array($emailOrAddressOrList)) {
|
||
|
$addressList->addMany($emailOrAddressOrList);
|
||
|
return;
|
||
|
}
|
||
|
if (! is_string($emailOrAddressOrList) && ! $emailOrAddressOrList instanceof Address\AddressInterface) {
|
||
|
throw new Exception\InvalidArgumentException(sprintf(
|
||
|
'%s expects a string, AddressInterface, array, AddressList, or Traversable as its first argument;'
|
||
|
. ' received "%s"',
|
||
|
$callingMethod,
|
||
|
(is_object($emailOrAddressOrList) ? get_class($emailOrAddressOrList) : gettype($emailOrAddressOrList))
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (is_string($emailOrAddressOrList) && $name === null) {
|
||
|
$addressList->addFromString($emailOrAddressOrList);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$addressList->add($emailOrAddressOrList, $name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Serialize to string
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function toString()
|
||
|
{
|
||
|
$headers = $this->getHeaders();
|
||
|
return $headers->toString()
|
||
|
. Headers::EOL
|
||
|
. $this->getBodyText();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Instantiate from raw message string
|
||
|
*
|
||
|
* @todo Restore body to Mime\Message
|
||
|
* @param string $rawMessage
|
||
|
* @return Message
|
||
|
*/
|
||
|
public static function fromString($rawMessage)
|
||
|
{
|
||
|
$message = new static();
|
||
|
|
||
|
/** @var Headers $headers */
|
||
|
$headers = null;
|
||
|
$content = null;
|
||
|
Mime\Decode::splitMessage($rawMessage, $headers, $content, Headers::EOL);
|
||
|
if ($headers->has('mime-version')) {
|
||
|
// todo - restore body to mime\message
|
||
|
}
|
||
|
$message->setHeaders($headers);
|
||
|
$message->setBody($content);
|
||
|
return $message;
|
||
|
}
|
||
|
}
|