mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-22 08:42:17 +02:00
N°5809 Update laminas/laminas-mail from 2.16.0 to 2.22.0
This commit is contained in:
@@ -5,10 +5,19 @@ namespace Laminas\Mail;
|
||||
use Laminas\Validator\EmailAddress as EmailAddressValidator;
|
||||
use Laminas\Validator\Hostname;
|
||||
|
||||
use function array_shift;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function trim;
|
||||
|
||||
class Address implements Address\AddressInterface
|
||||
{
|
||||
/** @var null|string */
|
||||
protected $comment;
|
||||
/** @var string */
|
||||
protected $email;
|
||||
/** @var null|string */
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
@@ -149,7 +158,7 @@ class Address implements Address\AddressInterface
|
||||
*/
|
||||
private function constructName()
|
||||
{
|
||||
$name = $this->getName();
|
||||
$name = $this->getName();
|
||||
$comment = $this->getComment();
|
||||
|
||||
if ($comment === null || $comment === '') {
|
||||
|
||||
@@ -4,24 +4,43 @@ namespace Laminas\Mail;
|
||||
|
||||
use Countable;
|
||||
use Iterator;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use ReturnTypeWillChange;
|
||||
|
||||
use function count;
|
||||
use function current;
|
||||
use function gettype;
|
||||
use function is_int;
|
||||
use function is_numeric;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* @implements Iterator<string, AddressInterface>
|
||||
* @final
|
||||
*/
|
||||
class AddressList implements Countable, Iterator
|
||||
{
|
||||
/**
|
||||
* List of Address objects we're managing
|
||||
*
|
||||
* @var array
|
||||
* @var array<string, AddressInterface>
|
||||
*/
|
||||
protected $addresses = [];
|
||||
|
||||
/**
|
||||
* Add an address to the list
|
||||
*
|
||||
* @param string|Address\AddressInterface $emailOrAddress
|
||||
* @param string|AddressInterface $emailOrAddress
|
||||
* @param null|string $name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function add($emailOrAddress, $name = null)
|
||||
{
|
||||
@@ -29,12 +48,12 @@ class AddressList implements Countable, Iterator
|
||||
$emailOrAddress = $this->createAddress($emailOrAddress, $name);
|
||||
}
|
||||
|
||||
if (! $emailOrAddress instanceof Address\AddressInterface) {
|
||||
if (! $emailOrAddress instanceof AddressInterface) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects an email address or %s\Address object as its first argument; received "%s"',
|
||||
__METHOD__,
|
||||
__NAMESPACE__,
|
||||
(is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
|
||||
is_object($emailOrAddress) ? $emailOrAddress::class : gettype($emailOrAddress)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -56,7 +75,7 @@ class AddressList implements Countable, Iterator
|
||||
*
|
||||
* @param array $addresses
|
||||
* @throws Exception\RuntimeException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function addMany(array $addresses)
|
||||
{
|
||||
@@ -69,7 +88,7 @@ class AddressList implements Countable, Iterator
|
||||
if (! is_string($key)) {
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
'Invalid key type in provided addresses array ("%s")',
|
||||
(is_object($key) ? get_class($key) : var_export($key, 1))
|
||||
is_object($key) ? $key::class : var_export($key, true)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -86,7 +105,7 @@ class AddressList implements Countable, Iterator
|
||||
* @param string $address
|
||||
* @param null|string $comment Comment associated with the address, if any.
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function addFromString($address, $comment = null)
|
||||
{
|
||||
@@ -97,8 +116,7 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Merge another address list into this one
|
||||
*
|
||||
* @param AddressList $addressList
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(self $addressList)
|
||||
{
|
||||
@@ -124,7 +142,7 @@ class AddressList implements Countable, Iterator
|
||||
* Get an address by email
|
||||
*
|
||||
* @param string $email
|
||||
* @return bool|Address\AddressInterface
|
||||
* @return false|AddressInterface
|
||||
*/
|
||||
public function get($email)
|
||||
{
|
||||
@@ -167,9 +185,10 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Rewind iterator
|
||||
*
|
||||
* @return mixed the value of the first addresses element, or false if the addresses is
|
||||
* empty.
|
||||
* @see addresses
|
||||
*
|
||||
* @return false|AddressInterface the value of the first addresses element, or false if the addresses is
|
||||
* empty.
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -180,7 +199,7 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Return current item in iteration
|
||||
*
|
||||
* @return Address
|
||||
* @return AddressInterface
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -202,9 +221,10 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Move to next item
|
||||
*
|
||||
* @return mixed the addresses value in the next place that's pointed to by the
|
||||
* internal array pointer, or false if there are no more elements.
|
||||
* @see addresses
|
||||
*
|
||||
* @return false|AddressInterface the addresses value in the next place that's pointed to by the
|
||||
* internal array pointer, or false if there are no more elements.
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -221,7 +241,7 @@ class AddressList implements Countable, Iterator
|
||||
public function valid()
|
||||
{
|
||||
$key = key($this->addresses);
|
||||
return ($key !== null && $key !== false);
|
||||
return $key !== null && $key !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +25,8 @@ class ConfigProvider
|
||||
{
|
||||
return [
|
||||
// Legacy Zend Framework aliases
|
||||
'aliases' => [
|
||||
\Zend\Mail\Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManager::class,
|
||||
'aliases' => [
|
||||
'Zend\Mail\Protocol\SmtpPluginManager' => Protocol\SmtpPluginManager::class,
|
||||
],
|
||||
'factories' => [
|
||||
Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManagerFactory::class,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Laminas\Mail\Exception;
|
||||
|
||||
interface ExceptionInterface
|
||||
use Throwable;
|
||||
|
||||
interface ExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6,7 +6,39 @@ use Laminas\Mail\Address;
|
||||
use Laminas\Mail\AddressList;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mail\Storage\Exception\RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function idn_to_ascii;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
use const IDNA_DEFAULT;
|
||||
use const IDNA_ERROR_BIDI;
|
||||
use const IDNA_ERROR_CONTEXTJ;
|
||||
use const IDNA_ERROR_DISALLOWED;
|
||||
use const IDNA_ERROR_DOMAIN_NAME_TOO_LONG;
|
||||
use const IDNA_ERROR_EMPTY_LABEL;
|
||||
use const IDNA_ERROR_HYPHEN_3_4;
|
||||
use const IDNA_ERROR_INVALID_ACE_LABEL;
|
||||
use const IDNA_ERROR_LABEL_HAS_DOT;
|
||||
use const IDNA_ERROR_LABEL_TOO_LONG;
|
||||
use const IDNA_ERROR_LEADING_COMBINING_MARK;
|
||||
use const IDNA_ERROR_LEADING_HYPHEN;
|
||||
use const IDNA_ERROR_PUNYCODE;
|
||||
use const IDNA_ERROR_TRAILING_HYPHEN;
|
||||
use const INTL_IDNA_VARIANT_UTS46;
|
||||
|
||||
/**
|
||||
* Base class for headers composing address lists (to, from, cc, bcc, reply-to)
|
||||
@@ -14,29 +46,25 @@ use Throwable;
|
||||
abstract class AbstractAddressList implements HeaderInterface
|
||||
{
|
||||
private const IDNA_ERROR_MAP = [
|
||||
IDNA_ERROR_EMPTY_LABEL => 'empty label',
|
||||
IDNA_ERROR_LABEL_TOO_LONG => 'label too long',
|
||||
IDNA_ERROR_DOMAIN_NAME_TOO_LONG => 'domain name too long',
|
||||
IDNA_ERROR_LEADING_HYPHEN => 'leading hyphen',
|
||||
IDNA_ERROR_TRAILING_HYPHEN => 'trailing hyphen',
|
||||
IDNA_ERROR_HYPHEN_3_4 => 'consecutive hyphens',
|
||||
IDNA_ERROR_EMPTY_LABEL => 'empty label',
|
||||
IDNA_ERROR_LABEL_TOO_LONG => 'label too long',
|
||||
IDNA_ERROR_DOMAIN_NAME_TOO_LONG => 'domain name too long',
|
||||
IDNA_ERROR_LEADING_HYPHEN => 'leading hyphen',
|
||||
IDNA_ERROR_TRAILING_HYPHEN => 'trailing hyphen',
|
||||
IDNA_ERROR_HYPHEN_3_4 => 'consecutive hyphens',
|
||||
IDNA_ERROR_LEADING_COMBINING_MARK => 'leading combining mark',
|
||||
IDNA_ERROR_DISALLOWED => 'disallowed',
|
||||
IDNA_ERROR_PUNYCODE => 'invalid punycode encoding',
|
||||
IDNA_ERROR_LABEL_HAS_DOT => 'has dot',
|
||||
IDNA_ERROR_INVALID_ACE_LABEL => 'label not in ASCII encoding',
|
||||
IDNA_ERROR_BIDI => 'fails bidirectional criteria',
|
||||
IDNA_ERROR_CONTEXTJ => 'one or more characters fail CONTEXTJ rule',
|
||||
IDNA_ERROR_DISALLOWED => 'disallowed',
|
||||
IDNA_ERROR_PUNYCODE => 'invalid punycode encoding',
|
||||
IDNA_ERROR_LABEL_HAS_DOT => 'has dot',
|
||||
IDNA_ERROR_INVALID_ACE_LABEL => 'label not in ASCII encoding',
|
||||
IDNA_ERROR_BIDI => 'fails bidirectional criteria',
|
||||
IDNA_ERROR_CONTEXTJ => 'one or more characters fail CONTEXTJ rule',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var AddressList
|
||||
*/
|
||||
/** @var AddressList */
|
||||
protected $addressList;
|
||||
|
||||
/**
|
||||
* @var string Normalized field name
|
||||
*/
|
||||
/** @var string Normalized field name */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
@@ -46,40 +74,42 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var string lower case field name
|
||||
*/
|
||||
/** @var string lower case field name */
|
||||
protected static $type;
|
||||
|
||||
/** @var string[] lower case aliases for the field name */
|
||||
protected static $typeAliases = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
|
||||
if (strtolower($fieldName) !== static::$type) {
|
||||
[$fieldName, $fieldValue] = GenericHeader::splitHeaderLine($headerLine);
|
||||
if ((strtolower($fieldName) !== static::$type) && ! in_array(strtolower($fieldName), static::$typeAliases)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Invalid header line for "%s" string',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
// split value on ","
|
||||
$fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
|
||||
$fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
|
||||
$values = ListParser::parse($fieldValue);
|
||||
$values = ListParser::parse($fieldValue);
|
||||
|
||||
$wasEncoded = false;
|
||||
$addresses = array_map(
|
||||
function ($value) use (&$wasEncoded) {
|
||||
$addresses = array_map(
|
||||
static function ($value) use (&$wasEncoded): ?Address {
|
||||
$decodedValue = HeaderWrap::mimeDecodeValue($value);
|
||||
$wasEncoded = $wasEncoded || ($decodedValue !== $value);
|
||||
|
||||
$value = trim($decodedValue);
|
||||
|
||||
$comments = self::getComments($value);
|
||||
$value = self::stripComments($value);
|
||||
|
||||
$value = preg_replace(
|
||||
$wasEncoded = $wasEncoded || ($decodedValue !== $value);
|
||||
$value = trim($decodedValue);
|
||||
$comments = self::getComments($value);
|
||||
$value = self::stripComments($value);
|
||||
$value = preg_replace(
|
||||
[
|
||||
'#(?<!\\\)"(.*)(?<!\\\)"#', // quoted-text
|
||||
'#(?<!\\\)"(.*)(?<!\\\)"#', // quoted-text
|
||||
'#\\\([\x01-\x09\x0b\x0c\x0e-\x7f])#', // quoted-pair
|
||||
],
|
||||
[
|
||||
@@ -88,12 +118,11 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
],
|
||||
$value
|
||||
);
|
||||
|
||||
return empty($value) ? null : Address::fromString($value, $comments);
|
||||
},
|
||||
$values
|
||||
);
|
||||
$addresses = array_filter($addresses);
|
||||
$addresses = array_filter($addresses);
|
||||
|
||||
$header = new static();
|
||||
if ($wasEncoded) {
|
||||
@@ -109,6 +138,9 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return $this->fieldName;
|
||||
@@ -116,18 +148,21 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
|
||||
/**
|
||||
* Safely convert UTF-8 encoded domain name to ASCII
|
||||
*
|
||||
* @param string $domainName the UTF-8 encoded email
|
||||
* @return string
|
||||
*/
|
||||
protected function idnToAscii($domainName): string
|
||||
{
|
||||
/** @psalm-var string|false $ascii */
|
||||
$ascii = idn_to_ascii($domainName, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $conversionInfo);
|
||||
if (false !== $ascii) {
|
||||
if (is_string($ascii)) {
|
||||
return $ascii;
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
$errors = (int) $conversionInfo['errors'];
|
||||
assert(is_array($conversionInfo));
|
||||
/* @psalm-var array{errors: numeric-string} $conversionInfo */
|
||||
$errors = (int) $conversionInfo['errors'];
|
||||
|
||||
foreach (self::IDNA_ERROR_MAP as $flag => $message) {
|
||||
if (($flag & $errors) === $flag) {
|
||||
@@ -141,6 +176,9 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$emails = [];
|
||||
@@ -151,12 +189,13 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
$name = $address->getName();
|
||||
|
||||
// quote $name if value requires so
|
||||
if (! empty($name) && (false !== strpos($name, ',') || false !== strpos($name, ';'))) {
|
||||
if (! empty($name) && (str_contains($name, ',') || str_contains($name, ';'))) {
|
||||
// FIXME: what if name contains double quote?
|
||||
$name = sprintf('"%s"', $name);
|
||||
}
|
||||
|
||||
if ($format === HeaderInterface::FORMAT_ENCODED
|
||||
if (
|
||||
$format === HeaderInterface::FORMAT_ENCODED
|
||||
&& 'ASCII' !== $encoding
|
||||
) {
|
||||
if (! empty($name)) {
|
||||
@@ -166,7 +205,7 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
if (preg_match('/^(.+)@([^@]+)$/', $email, $matches)) {
|
||||
$localPart = $matches[1];
|
||||
$hostname = $this->idnToAscii($matches[2]);
|
||||
$email = sprintf('%s@%s', $localPart, $hostname);
|
||||
$email = sprintf('%s@%s', $localPart, $hostname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,12 +226,19 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return implode(',' . Headers::FOLDING, $emails);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return $this->encoding;
|
||||
@@ -200,8 +246,6 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
|
||||
/**
|
||||
* Set address list for this header
|
||||
*
|
||||
* @param AddressList $addressList
|
||||
*/
|
||||
public function setAddressList(AddressList $addressList)
|
||||
{
|
||||
@@ -221,11 +265,14 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return $this->addressList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$name = $this->getFieldName();
|
||||
$value = $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
return (empty($value)) ? '' : sprintf('%s: %s', $name, $value);
|
||||
return empty($value) ? '' : sprintf('%s: %s', $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,9 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class Bcc extends AbstractAddressList
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName = 'Bcc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected static $type = 'bcc';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class Cc extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'Cc';
|
||||
/** @var string */
|
||||
protected static $type = 'cc';
|
||||
}
|
||||
|
||||
@@ -5,6 +5,21 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
use function is_numeric;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
use function var_export;
|
||||
|
||||
class ContentDisposition implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
@@ -14,9 +29,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public const MAX_PARAMETER_LENGTH = 76;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $disposition = 'inline';
|
||||
|
||||
/**
|
||||
@@ -26,9 +39,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
@@ -36,32 +47,32 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-disposition') {
|
||||
if (! in_array(strtolower($name), ['contentdisposition', 'content_disposition', 'content-disposition'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Disposition string');
|
||||
}
|
||||
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$parts = explode(';', $value, 2);
|
||||
|
||||
$header = new static();
|
||||
$header->setDisposition($parts[0]);
|
||||
|
||||
if (isset($parts[1])) {
|
||||
$values = ListParser::parse(trim($parts[1]), [';', '=']);
|
||||
$length = count($values);
|
||||
$values = ListParser::parse(trim($parts[1]), [';', '=']);
|
||||
$length = count($values);
|
||||
$continuedValues = [];
|
||||
|
||||
for ($i = 0; $i < $length; $i += 2) {
|
||||
$value = $values[$i + 1];
|
||||
$value = trim($value, "'\" \t\n\r\0\x0B");
|
||||
$name = trim($values[$i], "'\" \t\n\r\0\x0B");
|
||||
$name = trim($values[$i], "'\" \t\n\r\0\x0B");
|
||||
|
||||
if (strpos($name, '*')) {
|
||||
list($name, $count) = explode('*', $name);
|
||||
[$name, $count] = explode('*', $name);
|
||||
// allow optional count:
|
||||
// Content-Disposition: attachment; filename*=UTF-8''%64%61%61%6D%69%2D%6D%C3%B5%72%76%2E%6A%70%67
|
||||
if ($count === "") {
|
||||
@@ -69,11 +80,11 @@ class ContentDisposition implements UnstructuredInterface
|
||||
}
|
||||
|
||||
if (! is_numeric($count)) {
|
||||
$type = gettype($count);
|
||||
$value = var_export($count, 1);
|
||||
$type = gettype($count);
|
||||
$value = var_export($count, true);
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
"Invalid header line for Content-Disposition string".
|
||||
" - count expected to be numeric, got %s with value %s",
|
||||
"Invalid header line for Content-Disposition string"
|
||||
. " - count expected to be numeric, got %s with value %s",
|
||||
$type,
|
||||
$value
|
||||
));
|
||||
@@ -92,8 +103,8 @@ class ContentDisposition implements UnstructuredInterface
|
||||
for ($i = 0, $iMax = count($values); $i < $iMax; $i++) {
|
||||
if (! isset($values[$i])) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'Invalid header line for Content-Disposition string - incomplete continuation'.
|
||||
'; HeaderLine: '.$headerLine
|
||||
'Invalid header line for Content-Disposition string - incomplete continuation'
|
||||
. '; HeaderLine: ' . $headerLine
|
||||
);
|
||||
}
|
||||
$value .= $values[$i];
|
||||
@@ -126,7 +137,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
foreach ($this->parameters as $attribute => $value) {
|
||||
$valueIsEncoded = false;
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
|
||||
$value = $this->getEncodedValue($value);
|
||||
$value = $this->getEncodedValue($value);
|
||||
$valueIsEncoded = true;
|
||||
}
|
||||
|
||||
@@ -152,13 +163,13 @@ class ContentDisposition implements UnstructuredInterface
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$i = 0;
|
||||
$fullLength = mb_strlen($value, 'UTF-8');
|
||||
while ($fullLength > 0) {
|
||||
$attributePart = $attribute . '*' . $i++ . '="';
|
||||
$attLen = mb_strlen($attributePart, 'UTF-8');
|
||||
$attLen = mb_strlen($attributePart, 'UTF-8');
|
||||
|
||||
$subPos = 1;
|
||||
$subPos = 1;
|
||||
$valuePart = '';
|
||||
while ($subPos <= $fullLength) {
|
||||
$sub = mb_substr($value, 0, $subPos, 'UTF-8');
|
||||
@@ -173,9 +184,9 @@ class ContentDisposition implements UnstructuredInterface
|
||||
$valuePart = $sub;
|
||||
}
|
||||
|
||||
$value = mb_substr($value, $subPos, null, 'UTF-8');
|
||||
$value = mb_substr($value, $subPos, null, 'UTF-8');
|
||||
$fullLength = mb_strlen($value, 'UTF-8');
|
||||
$result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"';
|
||||
$result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,9 +201,9 @@ class ContentDisposition implements UnstructuredInterface
|
||||
protected function getEncodedValue($value)
|
||||
{
|
||||
$configuredEncoding = $this->encoding;
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = $configuredEncoding;
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = $configuredEncoding;
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -253,7 +264,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public function setParameter($name, $value)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
$name = strtolower($name);
|
||||
|
||||
if (! HeaderValue::isValid($name)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
class ContentTransferEncoding implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* Allowed Content-Transfer-Encoding parameters specified by RFC 1521
|
||||
* (reduced set)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $allowedTransferEncodings = [
|
||||
@@ -21,23 +27,28 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
*/
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $transferEncoding;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-transfer-encoding') {
|
||||
if (
|
||||
! in_array(
|
||||
strtolower($name),
|
||||
['contenttransferencoding', 'content_transfer_encoding', 'content-transfer-encoding']
|
||||
)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Transfer-Encoding string');
|
||||
}
|
||||
|
||||
@@ -47,27 +58,43 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Content-Transfer-Encoding';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->transferEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// Header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Content-Transfer-Encoding: ' . $this->getFieldValue();
|
||||
@@ -87,7 +114,7 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
|
||||
if (! in_array($transferEncoding, static::$allowedTransferEncodings)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects one of "'. implode(', ', static::$allowedTransferEncodings) . '"; received "%s"',
|
||||
'%s expects one of "' . implode(', ', static::$allowedTransferEncodings) . '"; received "%s"',
|
||||
__METHOD__,
|
||||
(string) $transferEncoding
|
||||
));
|
||||
|
||||
@@ -5,11 +5,19 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
class ContentType implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
@@ -19,22 +27,24 @@ class ContentType implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-type') {
|
||||
if (! in_array(strtolower($name), ['contenttype', 'content_type', 'content-type'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Type string');
|
||||
}
|
||||
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$parts = explode(';', $value, 2);
|
||||
|
||||
$header = new static();
|
||||
@@ -54,11 +64,17 @@ class ContentType implements UnstructuredInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Content-Type';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$prepared = $this->type;
|
||||
@@ -70,7 +86,7 @@ class ContentType implements UnstructuredInterface
|
||||
foreach ($this->parameters as $attribute => $value) {
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = 'ASCII';
|
||||
}
|
||||
|
||||
@@ -80,17 +96,27 @@ class ContentType implements UnstructuredInterface
|
||||
return implode(';' . Headers::FOLDING, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Content-Type: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
@@ -132,8 +158,8 @@ class ContentType implements UnstructuredInterface
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return ContentType
|
||||
* @throws Exception\InvalidArgumentException for parameter names that do not follow RFC 2822
|
||||
* @throws Exception\InvalidArgumentException for parameter values that do not follow RFC 2822
|
||||
* @throws Exception\InvalidArgumentException For parameter names that do not follow RFC 2822.
|
||||
* @throws Exception\InvalidArgumentException For parameter values that do not follow RFC 2822.
|
||||
*/
|
||||
public function addParameter($name, $value)
|
||||
{
|
||||
|
||||
@@ -2,31 +2,36 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @todo Add accessors for setting date from DateTime, Laminas\Date, or a string
|
||||
*/
|
||||
class Date implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'date') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Date string');
|
||||
}
|
||||
|
||||
$header = new static($value);
|
||||
|
||||
return $header;
|
||||
return new static($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
if (! HeaderValue::isValid($value)) {
|
||||
@@ -35,27 +40,43 @@ class Date implements HeaderInterface
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Date';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Date: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class From extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'From';
|
||||
/** @var string */
|
||||
protected static $type = 'from';
|
||||
}
|
||||
|
||||
@@ -5,16 +5,20 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Header\Exception\InvalidArgumentException;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function is_string;
|
||||
use function ltrim;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use function ucwords;
|
||||
|
||||
class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldValue = '';
|
||||
|
||||
/**
|
||||
@@ -30,11 +34,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = self::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
$header = new static($name, $value);
|
||||
|
||||
return $header;
|
||||
[$name, $value] = self::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
return new static($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,21 +44,21 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return string[] `name` in the first index and `value` in the second.
|
||||
* @throws Exception\InvalidArgumentException If header does not match with the format ``name:value``
|
||||
* @throws InvalidArgumentException If header does not match with the format ``name:value``.
|
||||
*/
|
||||
public static function splitHeaderLine($headerLine)
|
||||
{
|
||||
$parts = explode(':', $headerLine, 2);
|
||||
if (count($parts) !== 2) {
|
||||
throw new Exception\InvalidArgumentException('Header must match with the format "name:value"');
|
||||
throw new InvalidArgumentException('Header must match with the format "name:value"');
|
||||
}
|
||||
|
||||
if (! HeaderName::isValid($parts[0])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header name detected');
|
||||
throw new InvalidArgumentException('Invalid header name detected');
|
||||
}
|
||||
|
||||
if (! HeaderValue::isValid($parts[1])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header value detected');
|
||||
throw new InvalidArgumentException('Invalid header value detected');
|
||||
}
|
||||
|
||||
$parts[1] = ltrim($parts[1]);
|
||||
@@ -93,14 +95,14 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
public function setFieldName($fieldName)
|
||||
{
|
||||
if (! is_string($fieldName) || empty($fieldName)) {
|
||||
throw new Exception\InvalidArgumentException('Header name must be a string');
|
||||
throw new InvalidArgumentException('Header name must be a string');
|
||||
}
|
||||
|
||||
// Pre-filter to normalize valid characters, change underscore to dash
|
||||
$fieldName = str_replace(' ', '-', ucwords(str_replace(['_', '-'], ' ', $fieldName)));
|
||||
|
||||
if (! HeaderName::isValid($fieldName)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
throw new InvalidArgumentException(
|
||||
'Header name must be composed of printable US-ASCII characters, except colon.'
|
||||
);
|
||||
}
|
||||
@@ -109,6 +111,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return $this->fieldName;
|
||||
@@ -126,7 +131,7 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
$fieldValue = (string) $fieldValue;
|
||||
|
||||
if (! HeaderWrap::canBeEncoded($fieldValue)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
throw new InvalidArgumentException(
|
||||
'Header value must be composed of printable US-ASCII characters and valid folding sequences.'
|
||||
);
|
||||
}
|
||||
@@ -137,6 +142,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format) {
|
||||
@@ -146,6 +154,10 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this->fieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
if ($encoding === $this->encoding) {
|
||||
@@ -173,6 +185,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -182,6 +197,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$name = $this->getFieldName();
|
||||
|
||||
@@ -2,15 +2,23 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function strpos;
|
||||
|
||||
/**
|
||||
* Generic class for Headers with multiple occurs in the same message
|
||||
*/
|
||||
class GenericMultiHeader extends GenericHeader implements MultipleHeadersInterface
|
||||
{
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return array|GenericHeader|GenericMultiHeader|static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$fieldValue = HeaderWrap::mimeDecodeValue($fieldValue);
|
||||
[$fieldName, $fieldValue] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$fieldValue = HeaderWrap::mimeDecodeValue($fieldValue);
|
||||
|
||||
if (strpos($fieldValue, ',')) {
|
||||
$headers = [];
|
||||
|
||||
@@ -16,15 +16,16 @@ interface HeaderInterface
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public const FORMAT_RAW = false;
|
||||
public const FORMAT_RAW = false;
|
||||
|
||||
/**
|
||||
* Factory to generate a header object from a string
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2822#section-2.2
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
* @throws Exception\InvalidArgumentException If the header does not match with RFC 2822 definition.
|
||||
* @see http://tools.ietf.org/html/rfc2822#section-2.2
|
||||
*/
|
||||
public static function fromString($headerLine);
|
||||
|
||||
@@ -38,7 +39,7 @@ interface HeaderInterface
|
||||
/**
|
||||
* Retrieve header value
|
||||
*
|
||||
* @param bool $format Return the value in Mime::Encoded or in Raw format
|
||||
* @param HeaderInterface::FORMAT_* $format Return the value in Mime::Encoded or in Raw format
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldValue($format = self::FORMAT_RAW);
|
||||
|
||||
@@ -9,9 +9,7 @@ use Laminas\Loader\PluginClassLoader;
|
||||
*/
|
||||
class HeaderLoader extends PluginClassLoader
|
||||
{
|
||||
/**
|
||||
* @var array Pre-aliased Header plugins
|
||||
*/
|
||||
/** @var array Pre-aliased Header plugins */
|
||||
protected $plugins = [
|
||||
'bcc' => Bcc::class,
|
||||
'cc' => Cc::class,
|
||||
|
||||
@@ -4,15 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* Plugin Class Loader implementation for HTTP headers
|
||||
*/
|
||||
final class HeaderLocator implements HeaderLocatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array Pre-aliased Header plugins
|
||||
*/
|
||||
private $plugins = [
|
||||
/** @var array Pre-aliased Header plugins */
|
||||
private array $plugins = [
|
||||
'bcc' => Bcc::class,
|
||||
'cc' => Cc::class,
|
||||
'contentdisposition' => ContentDisposition::class,
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function ord;
|
||||
use function strlen;
|
||||
|
||||
final class HeaderName
|
||||
{
|
||||
/**
|
||||
@@ -15,6 +18,7 @@ final class HeaderName
|
||||
* Filter the header name according to RFC 2822
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function ord;
|
||||
use function strlen;
|
||||
|
||||
final class HeaderValue
|
||||
{
|
||||
/**
|
||||
@@ -15,6 +19,7 @@ final class HeaderValue
|
||||
* Filter the header value according to RFC 2822
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
@@ -44,7 +49,7 @@ final class HeaderValue
|
||||
}
|
||||
|
||||
$result .= "\r\n ";
|
||||
$i += 2;
|
||||
$i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -58,6 +63,7 @@ final class HeaderValue
|
||||
* Determine if the header value contains any invalid characters.
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -5,17 +5,35 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function array_reduce;
|
||||
use function explode;
|
||||
use function extension_loaded;
|
||||
use function iconv_mime_decode;
|
||||
use function iconv_mime_encode;
|
||||
use function imap_mime_header_decode;
|
||||
use function imap_utf8;
|
||||
use function implode;
|
||||
use function str_contains;
|
||||
use function str_pad;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use function wordwrap;
|
||||
|
||||
use const ICONV_MIME_DECODE_CONTINUE_ON_ERROR;
|
||||
|
||||
/**
|
||||
* Utility class used for creating wrapped or MIME-encoded versions of header
|
||||
* values.
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class HeaderWrap
|
||||
{
|
||||
/**
|
||||
* Wrap a long header line
|
||||
*
|
||||
* @param string $value
|
||||
* @param HeaderInterface $header
|
||||
* @return string
|
||||
*/
|
||||
public static function wrap($value, HeaderInterface $header)
|
||||
@@ -34,23 +52,33 @@ abstract class HeaderWrap
|
||||
* Wrap at 78 characters or before, based on whitespace.
|
||||
*
|
||||
* @param string $value
|
||||
* @param HeaderInterface $header
|
||||
* @return string
|
||||
*/
|
||||
protected static function wrapUnstructuredHeader($value, HeaderInterface $header)
|
||||
{
|
||||
$encoding = $header->getEncoding();
|
||||
$headerNameColonSize = strlen($header->getFieldName() . ': ');
|
||||
$encoding = $header->getEncoding();
|
||||
|
||||
if ($encoding == 'ASCII') {
|
||||
return wordwrap($value, 78, Headers::FOLDING);
|
||||
/*
|
||||
* Before folding the header line, it is necessary to calculate the length of the
|
||||
* entire header (including the name and colon). We need to put a stub at the
|
||||
* beginning of the value so that the folding is performed correctly.
|
||||
*/
|
||||
$headerLine = str_pad('0', $headerNameColonSize, '0') . $value;
|
||||
$foldedHeaderLine = wordwrap($headerLine, 78, Headers::FOLDING);
|
||||
|
||||
// Remove the stub and return the header folded value.
|
||||
return substr($foldedHeaderLine, $headerNameColonSize);
|
||||
}
|
||||
return static::mimeEncodeValue($value, $encoding, 78);
|
||||
|
||||
return static::mimeEncodeValue($value, $encoding, 78, $headerNameColonSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a structured header line
|
||||
*
|
||||
* @param string $value
|
||||
* @param StructuredInterface $header
|
||||
* @return string
|
||||
*/
|
||||
protected static function wrapStructuredHeader($value, StructuredInterface $header)
|
||||
@@ -76,14 +104,19 @@ abstract class HeaderWrap
|
||||
* Performs quoted-printable encoding on a value, setting maximum
|
||||
* line-length to 998.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $encoding
|
||||
* @param int $lineLength maximum line-length, by default 998
|
||||
* @param string $value
|
||||
* @param string $encoding
|
||||
* @param int $lineLength Maximum line-length, by default 998
|
||||
* @param positive-int|0 $firstLineGapSize When folding a line, it is necessary to calculate
|
||||
* the length of the entire line (together with the
|
||||
* header name). Therefore, you can specify the header
|
||||
* name and colon length in this argument to fold the
|
||||
* string properly.
|
||||
* @return string Returns the mime encode value without the last line ending
|
||||
*/
|
||||
public static function mimeEncodeValue($value, $encoding, $lineLength = 998)
|
||||
public static function mimeEncodeValue($value, $encoding, $lineLength = 998, $firstLineGapSize = 0)
|
||||
{
|
||||
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL);
|
||||
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL, $firstLineGapSize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,9 +142,7 @@ abstract class HeaderWrap
|
||||
if (self::isNotDecoded($value, $decodedValue) && extension_loaded('imap')) {
|
||||
return array_reduce(
|
||||
imap_mime_header_decode(imap_utf8($value)),
|
||||
function ($accumulator, $headerPart) {
|
||||
return $accumulator . $headerPart->text;
|
||||
},
|
||||
static fn($accumulator, $headerPart) => $accumulator . $headerPart->text,
|
||||
''
|
||||
);
|
||||
}
|
||||
@@ -119,11 +150,11 @@ abstract class HeaderWrap
|
||||
return $decodedValue;
|
||||
}
|
||||
|
||||
private static function isNotDecoded($originalValue, $value)
|
||||
private static function isNotDecoded(string $originalValue, string $value): bool
|
||||
{
|
||||
return 0 === strpos($value, '=?')
|
||||
return str_starts_with($value, '=?')
|
||||
&& strlen($value) - 2 === strpos($value, '?=')
|
||||
&& false !== strpos($originalValue, $value);
|
||||
&& str_contains($originalValue, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,18 +169,18 @@ abstract class HeaderWrap
|
||||
// "test" -> 4
|
||||
// "x-test: =?ISO-8859-1?B?dGVzdA==?=" -> 33
|
||||
// 8 +2 +3 +3 -> 16
|
||||
$charset = 'UTF-8';
|
||||
$charset = 'UTF-8';
|
||||
$lineLength = strlen($value) * 4 + strlen($charset) + 16;
|
||||
|
||||
$preferences = [
|
||||
'scheme' => 'Q',
|
||||
'input-charset' => $charset,
|
||||
'scheme' => 'Q',
|
||||
'input-charset' => $charset,
|
||||
'output-charset' => $charset,
|
||||
'line-length' => $lineLength,
|
||||
'line-length' => $lineLength,
|
||||
];
|
||||
|
||||
$encoded = iconv_mime_encode('x-test', $value, $preferences);
|
||||
|
||||
return (false !== $encoded);
|
||||
return false !== $encoded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,27 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function array_map;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-3.6.4
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class IdentificationField implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string lower case field name
|
||||
*/
|
||||
/** @var string lower case field name */
|
||||
protected static $type;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
protected $messageIds;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
@@ -30,11 +33,11 @@ abstract class IdentificationField implements HeaderInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
if (strtolower($name) !== static::$type) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Invalid header line for "%s" string',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
@@ -69,14 +72,11 @@ abstract class IdentificationField implements HeaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $format
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return implode(Headers::FOLDING, array_map(function ($id) {
|
||||
return sprintf('<%s>', $id);
|
||||
}, $this->messageIds));
|
||||
return implode(Headers::FOLDING, array_map(static fn($id) => sprintf('<%s>', $id), $this->messageIds));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +114,8 @@ abstract class IdentificationField implements HeaderInterface
|
||||
public function setIds($ids)
|
||||
{
|
||||
foreach ($ids as $id) {
|
||||
if (! HeaderValue::isValid($id)
|
||||
if (
|
||||
! HeaderValue::isValid($id)
|
||||
|| preg_match("/[\r\n]/", $id)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid ID detected');
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class InReplyTo extends IdentificationField
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'In-Reply-To';
|
||||
/** @var string */
|
||||
protected static $type = 'in-reply-to';
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -35,14 +36,14 @@ class ListParser
|
||||
// If we are in an escape sequence, append the character and continue.
|
||||
if ($inEscape) {
|
||||
$currentValue .= $char;
|
||||
$inEscape = false;
|
||||
$inEscape = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we are not in a quoted string, and have a delimiter, append
|
||||
// the current value to the list, and reset the current value.
|
||||
if (in_array($char, $delims, true) && ! $inQuote) {
|
||||
$values [] = $currentValue;
|
||||
$values [] = $currentValue;
|
||||
$currentValue = '';
|
||||
continue;
|
||||
}
|
||||
@@ -66,7 +67,7 @@ class ListParser
|
||||
// we reset our quote status and the currently opened quote
|
||||
// delimiter.
|
||||
if ($char === $currentQuoteDelim) {
|
||||
$inQuote = false;
|
||||
$inQuote = false;
|
||||
$currentQuoteDelim = null;
|
||||
continue;
|
||||
}
|
||||
@@ -78,7 +79,7 @@ class ListParser
|
||||
}
|
||||
|
||||
// Otherwise, we're starting a quoted string.
|
||||
$inQuote = true;
|
||||
$inQuote = true;
|
||||
$currentQuoteDelim = $char;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,29 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function getmypid;
|
||||
use function mt_rand;
|
||||
use function php_uname;
|
||||
use function preg_match;
|
||||
use function sha1;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function time;
|
||||
use function trim;
|
||||
|
||||
class MessageId implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $messageId;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'message-id') {
|
||||
@@ -25,27 +37,43 @@ class MessageId implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Message-ID';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Message-ID: ' . $this->getFieldValue();
|
||||
@@ -65,7 +93,8 @@ class MessageId implements HeaderInterface
|
||||
$id = trim($id, '<>');
|
||||
}
|
||||
|
||||
if (! HeaderValue::isValid($id)
|
||||
if (
|
||||
! HeaderValue::isValid($id)
|
||||
|| preg_match("/[\r\n]/", $id)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid ID detected');
|
||||
|
||||
@@ -2,20 +2,26 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function strtolower;
|
||||
|
||||
class MimeVersion implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string Version string
|
||||
*/
|
||||
/** @var string Version string */
|
||||
protected $version = '1.0';
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'mime-version') {
|
||||
if (! in_array(strtolower($name), ['mimeversion', 'mime_version', 'mime-version'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for MIME-Version string');
|
||||
}
|
||||
|
||||
@@ -28,27 +34,43 @@ class MimeVersion implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'MIME-Version';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'MIME-Version: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,31 +4,37 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function implode;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @todo Allow setting date from DateTime, Laminas\Date, or string
|
||||
*/
|
||||
class Received implements HeaderInterface, MultipleHeadersInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'received') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Received string');
|
||||
}
|
||||
|
||||
$header = new static($value);
|
||||
|
||||
return $header;
|
||||
return new static($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct($value = '')
|
||||
{
|
||||
if (! HeaderValue::isValid($value)) {
|
||||
@@ -37,27 +43,43 @@ class Received implements HeaderInterface, MultipleHeadersInterface
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Received';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Received: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class References extends IdentificationField
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'References';
|
||||
/** @var string */
|
||||
protected static $type = 'references';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class ReplyTo extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'Reply-To';
|
||||
/** @var string */
|
||||
protected static $type = 'reply-to';
|
||||
/** @var string[] */
|
||||
protected static $typeAliases = ['replyto', 'reply_to'];
|
||||
}
|
||||
|
||||
@@ -3,8 +3,17 @@
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Sender header class methods.
|
||||
*
|
||||
@@ -13,9 +22,7 @@ use Laminas\Mime\Mime;
|
||||
*/
|
||||
class Sender implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var \Laminas\Mail\Address\AddressInterface
|
||||
*/
|
||||
/** @var AddressInterface */
|
||||
protected $address;
|
||||
|
||||
/**
|
||||
@@ -25,21 +32,26 @@ class Sender implements HeaderInterface
|
||||
*/
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'sender') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header name for Sender string');
|
||||
}
|
||||
|
||||
$header = new static();
|
||||
$header = new static();
|
||||
|
||||
/**
|
||||
* matches the header value so that the email must be enclosed by < > when a name is present
|
||||
* 'name' and 'email' capture groups correspond respectively to 'display-name' and 'addr-spec' in the ABNF
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-3.4
|
||||
*/
|
||||
$hasMatches = preg_match(
|
||||
@@ -63,11 +75,17 @@ class Sender implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Sender';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (! $this->address instanceof Mail\Address\AddressInterface) {
|
||||
@@ -81,7 +99,7 @@ class Sender implements HeaderInterface
|
||||
if ($format == HeaderInterface::FORMAT_ENCODED) {
|
||||
$encoding = $this->getEncoding();
|
||||
if ('ASCII' !== $encoding) {
|
||||
$name = HeaderWrap::mimeEncodeValue($name, $encoding);
|
||||
$name = HeaderWrap::mimeEncodeValue($name, $encoding);
|
||||
}
|
||||
}
|
||||
$email = sprintf('%s %s', $name, $email);
|
||||
@@ -90,12 +108,19 @@ class Sender implements HeaderInterface
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -107,6 +132,9 @@ class Sender implements HeaderInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Sender: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
@@ -115,7 +143,7 @@ class Sender implements HeaderInterface
|
||||
/**
|
||||
* Set the address used in this header
|
||||
*
|
||||
* @param string|\Laminas\Mail\Address\AddressInterface $emailOrAddress
|
||||
* @param string|AddressInterface $emailOrAddress
|
||||
* @param null|string $name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return Sender
|
||||
@@ -128,7 +156,7 @@ class Sender implements HeaderInterface
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects a string or AddressInterface object; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
|
||||
is_object($emailOrAddress) ? $emailOrAddress::class : gettype($emailOrAddress)
|
||||
));
|
||||
}
|
||||
$this->address = $emailOrAddress;
|
||||
@@ -138,7 +166,7 @@ class Sender implements HeaderInterface
|
||||
/**
|
||||
* Retrieve the internal address from this header
|
||||
*
|
||||
* @return \Laminas\Mail\Address\AddressInterface|null
|
||||
* @return AddressInterface|null
|
||||
*/
|
||||
public function getAddress()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
|
||||
/**
|
||||
* Subject header class methods.
|
||||
*
|
||||
@@ -12,9 +15,7 @@ use Laminas\Mime\Mime;
|
||||
*/
|
||||
class Subject implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $subject = '';
|
||||
|
||||
/**
|
||||
@@ -24,10 +25,14 @@ class Subject implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'subject') {
|
||||
@@ -40,11 +45,17 @@ class Subject implements UnstructuredInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Subject';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format) {
|
||||
@@ -54,6 +65,10 @@ class Subject implements UnstructuredInterface
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
if ($encoding === $this->encoding) {
|
||||
@@ -81,6 +96,9 @@ class Subject implements UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -90,6 +108,10 @@ class Subject implements UnstructuredInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $subject
|
||||
* @return self
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$subject = (string) $subject;
|
||||
@@ -106,6 +128,9 @@ class Subject implements UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Subject: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class To extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'To';
|
||||
/** @var string */
|
||||
protected static $type = 'to';
|
||||
}
|
||||
|
||||
@@ -10,13 +10,40 @@ use Iterator;
|
||||
use Laminas\Loader\PluginClassLocator;
|
||||
use Laminas\Mail\Header\GenericHeader;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Header\HeaderLocatorInterface;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
use function array_keys;
|
||||
use function array_shift;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function current;
|
||||
use function explode;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function key;
|
||||
use function next;
|
||||
use function preg_match;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trigger_error;
|
||||
use function trim;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Basic mail headers collection functionality
|
||||
*
|
||||
* Handles aggregation of headers
|
||||
*
|
||||
* @implements Iterator<int, HeaderInterface>
|
||||
*/
|
||||
class Headers implements Countable, Iterator
|
||||
{
|
||||
@@ -26,10 +53,7 @@ class Headers implements Countable, Iterator
|
||||
/** @var string Start of Line when folding */
|
||||
public const FOLDING = "\r\n ";
|
||||
|
||||
/**
|
||||
* @var null|Header\HeaderLocatorInterface
|
||||
*/
|
||||
private $headerLocator;
|
||||
private ?HeaderLocatorInterface $headerLocator = null;
|
||||
|
||||
/**
|
||||
* @todo Remove for 3.0.0.
|
||||
@@ -37,14 +61,10 @@ class Headers implements Countable, Iterator
|
||||
*/
|
||||
protected $pluginClassLoader;
|
||||
|
||||
/**
|
||||
* @var array key names for $headers array
|
||||
*/
|
||||
/** @var list<string> key names for $headers array */
|
||||
protected $headersKeys = [];
|
||||
|
||||
/**
|
||||
* @var Header\HeaderInterface[] instances
|
||||
*/
|
||||
/** @var list<HeaderInterface> instances */
|
||||
protected $headers = [];
|
||||
|
||||
/**
|
||||
@@ -62,18 +82,18 @@ class Headers implements Countable, Iterator
|
||||
* will be lazy loaded)
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $EOL EOL string; defaults to {@link EOL}
|
||||
* @throws Exception\RuntimeException
|
||||
* @param string $eol EOL string; defaults to {@link EOL}
|
||||
* @return Headers
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public static function fromString($string, $EOL = self::EOL)
|
||||
public static function fromString($string, $eol = self::EOL)
|
||||
{
|
||||
$headers = new static();
|
||||
$currentLine = '';
|
||||
$emptyLine = 0;
|
||||
|
||||
// iterate the header lines, some might be continuations
|
||||
$lines = explode($EOL, $string);
|
||||
$lines = explode($eol, $string);
|
||||
$total = count($lines);
|
||||
for ($i = 0; $i < $total; $i += 1) {
|
||||
$line = $lines[$i];
|
||||
@@ -128,6 +148,7 @@ class Headers implements Countable, Iterator
|
||||
* Set an alternate PluginClassLocator implementation for loading header classes.
|
||||
*
|
||||
* @deprecated since 2.12.0
|
||||
*
|
||||
* @todo Remove for version 3.0.0
|
||||
* @return $this
|
||||
*/
|
||||
@@ -137,7 +158,7 @@ class Headers implements Countable, Iterator
|
||||
@trigger_error(sprintf(
|
||||
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::setHeaderLocator() instead',
|
||||
__METHOD__,
|
||||
__CLASS__
|
||||
self::class
|
||||
), E_USER_DEPRECATED);
|
||||
|
||||
$this->pluginClassLoader = $pluginClassLoader;
|
||||
@@ -150,6 +171,7 @@ class Headers implements Countable, Iterator
|
||||
* Lazyloads a Header\HeaderLoader if necessary.
|
||||
*
|
||||
* @deprecated since 2.12.0
|
||||
*
|
||||
* @todo Remove for version 3.0.0
|
||||
* @return PluginClassLocator
|
||||
*/
|
||||
@@ -159,7 +181,7 @@ class Headers implements Countable, Iterator
|
||||
@trigger_error(sprintf(
|
||||
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::getHeaderLocator() instead',
|
||||
__METHOD__,
|
||||
__CLASS__
|
||||
self::class
|
||||
), E_USER_DEPRECATED);
|
||||
|
||||
if (! $this->pluginClassLoader) {
|
||||
@@ -174,11 +196,14 @@ class Headers implements Countable, Iterator
|
||||
*
|
||||
* Lazyloads a Header\HeaderLocator instance if necessary.
|
||||
*/
|
||||
public function getHeaderLocator(): Header\HeaderLocatorInterface
|
||||
public function getHeaderLocator(): HeaderLocatorInterface
|
||||
{
|
||||
if (! $this->headerLocator) {
|
||||
$this->setHeaderLocator(new Header\HeaderLocator());
|
||||
}
|
||||
|
||||
assert($this->headerLocator instanceof HeaderLocatorInterface);
|
||||
|
||||
return $this->headerLocator;
|
||||
}
|
||||
|
||||
@@ -186,7 +211,7 @@ class Headers implements Countable, Iterator
|
||||
* @todo Return self when we update to 7.4 or later as minimum PHP version.
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeaderLocator(Header\HeaderLocatorInterface $headerLocator)
|
||||
public function setHeaderLocator(HeaderLocatorInterface $headerLocator)
|
||||
{
|
||||
$this->headerLocator = $headerLocator;
|
||||
return $this;
|
||||
@@ -231,7 +256,7 @@ class Headers implements Countable, Iterator
|
||||
if (! is_array($headers) && ! $headers instanceof Traversable) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Expected array or Traversable; received "%s"',
|
||||
(is_object($headers) ? get_class($headers) : gettype($headers))
|
||||
is_object($headers) ? $headers::class : gettype($headers)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -271,9 +296,9 @@ class Headers implements Countable, Iterator
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects its first argument to be a string; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($headerFieldNameOrLine)
|
||||
? get_class($headerFieldNameOrLine)
|
||||
: gettype($headerFieldNameOrLine))
|
||||
is_object($headerFieldNameOrLine)
|
||||
? $headerFieldNameOrLine::class
|
||||
: gettype($headerFieldNameOrLine)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -288,7 +313,7 @@ class Headers implements Countable, Iterator
|
||||
$this->addHeader(Header\GenericMultiHeader::fromString($headerFieldNameOrLine . ':' . $i));
|
||||
}
|
||||
} else {
|
||||
$this->addHeader(Header\GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
|
||||
$this->addHeader(GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -297,14 +322,13 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Add a Header\Interface to this container, for raw values see {@link addHeaderLine()} and {@link addHeaders()}
|
||||
*
|
||||
* @param Header\HeaderInterface $header
|
||||
* @return Headers
|
||||
*/
|
||||
public function addHeader(Header\HeaderInterface $header)
|
||||
public function addHeader(HeaderInterface $header)
|
||||
{
|
||||
$key = $this->normalizeFieldName($header->getFieldName());
|
||||
$key = $this->normalizeFieldName($header->getFieldName());
|
||||
$this->headersKeys[] = $key;
|
||||
$this->headers[] = $header;
|
||||
$this->headers[] = $header;
|
||||
if ($this->getEncoding() !== 'ASCII') {
|
||||
$header->setEncoding($this->getEncoding());
|
||||
}
|
||||
@@ -314,7 +338,7 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Remove a Header from the container
|
||||
*
|
||||
* @param string|Header\HeaderInterface field name or specific header instance to remove
|
||||
* @param string|HeaderInterface $instanceOrFieldName field name or specific header instance to remove
|
||||
* @return bool
|
||||
*/
|
||||
public function removeHeader($instanceOrFieldName)
|
||||
@@ -323,8 +347,8 @@ class Headers implements Countable, Iterator
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s requires a string or %s instance; received %s',
|
||||
__METHOD__,
|
||||
Header\HeaderInterface::class,
|
||||
is_object($instanceOrFieldName) ? get_class($instanceOrFieldName) : gettype($instanceOrFieldName)
|
||||
HeaderInterface::class,
|
||||
is_object($instanceOrFieldName) ? $instanceOrFieldName::class : gettype($instanceOrFieldName)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -333,7 +357,7 @@ class Headers implements Countable, Iterator
|
||||
}
|
||||
|
||||
if (is_string($instanceOrFieldName)) {
|
||||
$key = $this->normalizeFieldName($instanceOrFieldName);
|
||||
$key = $this->normalizeFieldName($instanceOrFieldName);
|
||||
$indexes = array_keys($this->headersKeys, $key, true);
|
||||
}
|
||||
|
||||
@@ -365,13 +389,13 @@ class Headers implements Countable, Iterator
|
||||
* Get all headers of a certain name/type
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool|ArrayIterator|Header\HeaderInterface Returns false if there is no headers with $name in this
|
||||
* @return false|ArrayIterator|HeaderInterface Returns false if there is no headers with $name in this
|
||||
* contain, an ArrayIterator if the header is a MultipleHeadersInterface instance and finally returns
|
||||
* HeaderInterface for the rest of cases.
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$key = $this->normalizeFieldName($name);
|
||||
$key = $this->normalizeFieldName($name);
|
||||
$results = [];
|
||||
|
||||
foreach (array_keys($this->headersKeys, $key, true) as $index) {
|
||||
@@ -409,7 +433,6 @@ class Headers implements Countable, Iterator
|
||||
|
||||
/**
|
||||
* Advance the pointer for this object as an iterator
|
||||
*
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -436,12 +459,11 @@ class Headers implements Countable, Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
{
|
||||
return (current($this->headers) !== false);
|
||||
return current($this->headers) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the internal pointer for this object as an iterator
|
||||
*
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -452,7 +474,7 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Return the current value for this iterator, lazy loading it if need be
|
||||
*
|
||||
* @return Header\HeaderInterface
|
||||
* @return HeaderInterface
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -500,13 +522,12 @@ class Headers implements Countable, Iterator
|
||||
* Return the headers container as an array
|
||||
*
|
||||
* @param bool $format Return the values in Mime::Encoded or in Raw format
|
||||
* @return array
|
||||
* @return array<string, list<string>|string>
|
||||
* @todo determine how to produce single line headers, if they are supported
|
||||
*/
|
||||
public function toArray($format = Header\HeaderInterface::FORMAT_RAW)
|
||||
public function toArray($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$headers = [];
|
||||
/* @var $header Header\HeaderInterface */
|
||||
foreach ($this->headers as $header) {
|
||||
if ($header instanceof Header\MultipleHeadersInterface) {
|
||||
$name = $header->getFieldName();
|
||||
@@ -528,6 +549,7 @@ class Headers implements Countable, Iterator
|
||||
*/
|
||||
public function forceLoading()
|
||||
{
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedForeach
|
||||
foreach ($this as $item) {
|
||||
// $item should now be loaded
|
||||
}
|
||||
@@ -538,11 +560,11 @@ class Headers implements Countable, Iterator
|
||||
* Create Header object from header line
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return Header\HeaderInterface|Header\HeaderInterface[]
|
||||
* @return HeaderInterface|HeaderInterface[]
|
||||
*/
|
||||
public function loadHeader($headerLine)
|
||||
{
|
||||
list($name) = Header\GenericHeader::splitHeaderLine($headerLine);
|
||||
[$name] = GenericHeader::splitHeaderLine($headerLine);
|
||||
|
||||
/** @var HeaderInterface $class */
|
||||
$class = $this->resolveHeaderClass($name);
|
||||
@@ -550,14 +572,14 @@ class Headers implements Countable, Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @param array-key $index
|
||||
* @return mixed
|
||||
*/
|
||||
protected function lazyLoadHeader($index)
|
||||
{
|
||||
$current = $this->headers[$index];
|
||||
|
||||
$key = $this->headersKeys[$index];
|
||||
$key = $this->headersKeys[$index];
|
||||
|
||||
/** @var GenericHeader $class */
|
||||
$class = $this->resolveHeaderClass($key);
|
||||
@@ -595,13 +617,13 @@ class Headers implements Countable, Iterator
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @return null|string
|
||||
*/
|
||||
private function resolveHeaderClass($key)
|
||||
{
|
||||
if ($this->pluginClassLoader) {
|
||||
return $this->pluginClassLoader->load($key) ?: Header\GenericHeader::class;
|
||||
return $this->pluginClassLoader->load($key) ?: GenericHeader::class;
|
||||
}
|
||||
return $this->getHeaderLocator()->get($key, Header\GenericHeader::class);
|
||||
return $this->getHeaderLocator()->get($key, GenericHeader::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Laminas\Mail;
|
||||
|
||||
use ArrayIterator;
|
||||
use Laminas\Mail\Header\Bcc;
|
||||
use Laminas\Mail\Header\Cc;
|
||||
use Laminas\Mail\Header\ContentType;
|
||||
@@ -13,6 +14,16 @@ use Laminas\Mail\Header\To;
|
||||
use Laminas\Mime;
|
||||
use Traversable;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function date;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
class Message
|
||||
{
|
||||
/**
|
||||
@@ -22,9 +33,7 @@ class Message
|
||||
*/
|
||||
protected $body;
|
||||
|
||||
/**
|
||||
* @var Headers
|
||||
*/
|
||||
/** @var Headers */
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
@@ -78,7 +87,6 @@ class Message
|
||||
/**
|
||||
* Compose headers
|
||||
*
|
||||
* @param Headers $headers
|
||||
* @return Message
|
||||
*/
|
||||
public function setHeaders(Headers $headers)
|
||||
@@ -297,11 +305,9 @@ class Message
|
||||
/**
|
||||
* setSender
|
||||
*
|
||||
* @param mixed $emailOrAddress
|
||||
* @param mixed $name
|
||||
* @return Message
|
||||
*/
|
||||
public function setSender($emailOrAddress, $name = null)
|
||||
public function setSender(mixed $emailOrAddress, mixed $name = null)
|
||||
{
|
||||
/** @var Sender $header */
|
||||
$header = $this->getHeaderByName('sender', Sender::class);
|
||||
@@ -385,7 +391,7 @@ class Message
|
||||
. ' object of type "%s" received',
|
||||
__METHOD__,
|
||||
Mime\Message::class,
|
||||
get_class($body)
|
||||
$body::class
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -402,7 +408,7 @@ class Message
|
||||
|
||||
// Multipart content headers
|
||||
if ($this->body->isMultiPart()) {
|
||||
$mime = $this->body->getMime();
|
||||
$mime = $this->body->getMime();
|
||||
|
||||
/** @var ContentType $header */
|
||||
$header = $this->getHeaderByName('content-type', ContentType::class);
|
||||
@@ -451,7 +457,7 @@ class Message
|
||||
*
|
||||
* @param string $headerName
|
||||
* @param string $headerClass
|
||||
* @return Header\HeaderInterface|\ArrayIterator header instance or collection of headers
|
||||
* @return Header\HeaderInterface|ArrayIterator header instance or collection of headers
|
||||
*/
|
||||
protected function getHeaderByName($headerName, $headerClass)
|
||||
{
|
||||
@@ -492,7 +498,7 @@ class Message
|
||||
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)
|
||||
$header::class
|
||||
));
|
||||
}
|
||||
return $header->getAddressList();
|
||||
@@ -503,7 +509,6 @@ class Message
|
||||
*
|
||||
* 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
|
||||
@@ -526,7 +531,7 @@ class Message
|
||||
'%s expects a string, AddressInterface, array, AddressList, or Traversable as its first argument;'
|
||||
. ' received "%s"',
|
||||
$callingMethod,
|
||||
(is_object($emailOrAddressOrList) ? get_class($emailOrAddressOrList) : gettype($emailOrAddressOrList))
|
||||
is_object($emailOrAddressOrList) ? $emailOrAddressOrList::class : gettype($emailOrAddressOrList)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -566,9 +571,9 @@ class Message
|
||||
$headers = null;
|
||||
$content = null;
|
||||
Mime\Decode::splitMessage($rawMessage, $headers, $content, Headers::EOL);
|
||||
if ($headers->has('mime-version')) {
|
||||
// if ($headers->has('mime-version')) {
|
||||
// todo - restore body to mime\message
|
||||
}
|
||||
// }
|
||||
$message->setHeaders($headers);
|
||||
$message->setBody($content);
|
||||
return $message;
|
||||
|
||||
@@ -4,6 +4,15 @@ namespace Laminas\Mail;
|
||||
|
||||
use Traversable;
|
||||
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
use function ucwords;
|
||||
|
||||
class MessageFactory
|
||||
{
|
||||
/**
|
||||
@@ -16,7 +25,7 @@ class MessageFactory
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'"%s" expects an array or Traversable; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($options) ? get_class($options) : gettype($options))
|
||||
is_object($options) ? $options::class : gettype($options)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Validator;
|
||||
use Laminas\Validator\ValidatorChain;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_resource;
|
||||
use function preg_split;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function str_starts_with;
|
||||
use function stream_get_meta_data;
|
||||
use function stream_set_timeout;
|
||||
use function stream_socket_client;
|
||||
|
||||
use const E_WARNING;
|
||||
use const PREG_SPLIT_DELIM_CAPTURE;
|
||||
|
||||
/**
|
||||
* Provides low-level methods for concrete adapters to communicate with a
|
||||
@@ -24,60 +46,57 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Maximum of the transaction log
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maximumLog = 64;
|
||||
|
||||
/**
|
||||
* Hostname or IP address of remote server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $host;
|
||||
|
||||
/**
|
||||
* Port number of connection
|
||||
* @var int
|
||||
*/
|
||||
protected $port;
|
||||
|
||||
/**
|
||||
* Instance of Laminas\Validator\ValidatorChain to check hostnames
|
||||
* @var \Laminas\Validator\ValidatorChain
|
||||
*
|
||||
* @var ValidatorChain
|
||||
*/
|
||||
protected $validHost;
|
||||
|
||||
/**
|
||||
* Socket connection resource
|
||||
*
|
||||
* @var null|resource
|
||||
*/
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* Last request sent to server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Array of server responses to last request
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Log of mail requests and server responses for a session
|
||||
* @var array
|
||||
*/
|
||||
private $log = [];
|
||||
private array $log = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
|
||||
* @param int $port OPTIONAL Port number (default: null)
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null)
|
||||
public function __construct($host = '127.0.0.1', protected $port = null)
|
||||
{
|
||||
$this->validHost = new Validator\ValidatorChain();
|
||||
$this->validHost->attach(new Validator\Hostname(Validator\Hostname::ALLOW_ALL));
|
||||
@@ -87,12 +106,10 @@ abstract class AbstractProtocol
|
||||
}
|
||||
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor to cleanup open resources
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
@@ -159,7 +176,6 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Reset the transaction log
|
||||
*
|
||||
*/
|
||||
public function resetLog()
|
||||
{
|
||||
@@ -187,6 +203,7 @@ abstract class AbstractProtocol
|
||||
* An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
|
||||
*
|
||||
* @deprecated Since 1.12.0. Implementations should use the ProtocolTrait::setupSocket() method instead.
|
||||
*
|
||||
* @todo Remove for 3.0.0.
|
||||
* @param string $remote Remote
|
||||
* @throws Exception\RuntimeException
|
||||
@@ -200,7 +217,7 @@ abstract class AbstractProtocol
|
||||
|
||||
// open connection
|
||||
set_error_handler(
|
||||
function ($error, $message = '') {
|
||||
static function ($error, $message = '') {
|
||||
throw new Exception\RuntimeException(sprintf('Could not open socket: %s', $message), $error);
|
||||
},
|
||||
E_WARNING
|
||||
@@ -224,7 +241,6 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Disconnect from remote host and free resource
|
||||
*
|
||||
*/
|
||||
// @codingStandardsIgnoreLine PSR2.Methods.MethodDeclaration.Underscore
|
||||
protected function _disconnect()
|
||||
@@ -316,15 +332,15 @@ abstract class AbstractProtocol
|
||||
protected function _expect($code, $timeout = null)
|
||||
{
|
||||
$this->response = [];
|
||||
$errMsg = '';
|
||||
$errMsg = '';
|
||||
|
||||
if (! is_array($code)) {
|
||||
$code = [$code];
|
||||
}
|
||||
|
||||
do {
|
||||
$this->response[] = $result = $this->_receive($timeout);
|
||||
list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$this->response[] = $result = $this->_receive($timeout);
|
||||
[$cmd, $more, $msg] = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
if ($errMsg !== '') {
|
||||
$errMsg .= ' ' . $msg;
|
||||
@@ -333,7 +349,7 @@ abstract class AbstractProtocol
|
||||
}
|
||||
|
||||
// The '-' message prefix indicates an information string instead of a response string.
|
||||
} while (strpos($more, '-') === 0);
|
||||
} while (str_starts_with($more, '-'));
|
||||
|
||||
if ($errMsg !== '') {
|
||||
throw new Exception\RuntimeException($errMsg);
|
||||
|
||||
@@ -2,6 +2,40 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Mail\Protocol\Exception\ExceptionInterface;
|
||||
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function array_search;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function current;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function func_get_args;
|
||||
use function func_num_args;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function key;
|
||||
use function next;
|
||||
use function preg_match;
|
||||
use function rtrim;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function str_starts_with;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const INF;
|
||||
|
||||
class Imap
|
||||
{
|
||||
use ProtocolTrait;
|
||||
@@ -11,13 +45,12 @@ class Imap
|
||||
*/
|
||||
public const TIMEOUT_CONNECTION = 30;
|
||||
|
||||
/**
|
||||
* @var null|resource
|
||||
*/
|
||||
/** @var null|resource */
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* counter for request tag
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $tagCount = 0;
|
||||
@@ -29,7 +62,7 @@ class Imap
|
||||
* @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
|
||||
* @param string|bool $ssl use ssl? 'SSL', 'TLS' or false
|
||||
* @param bool $novalidatecert set to true to skip SSL certificate validation
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct($host = '', $port = null, $ssl = false, $novalidatecert = false)
|
||||
{
|
||||
@@ -60,7 +93,7 @@ class Imap
|
||||
public function connect($host, $port = null, $ssl = false)
|
||||
{
|
||||
$transport = 'tcp';
|
||||
$isTls = false;
|
||||
$isTls = false;
|
||||
|
||||
if ($ssl) {
|
||||
$ssl = strtolower($ssl);
|
||||
@@ -123,7 +156,7 @@ class Imap
|
||||
protected function assumedNextLine($start)
|
||||
{
|
||||
$line = $this->nextLine();
|
||||
return strpos($line, $start) === 0;
|
||||
return str_starts_with($line, $start);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +170,7 @@ class Imap
|
||||
$line = $this->nextLine();
|
||||
|
||||
// separate tag from line
|
||||
list($tag, $line) = explode(' ', $line, 2);
|
||||
[$tag, $line] = explode(' ', $line, 2);
|
||||
|
||||
return $line;
|
||||
}
|
||||
@@ -151,7 +184,7 @@ class Imap
|
||||
protected function decodeLine($line)
|
||||
{
|
||||
$tokens = [];
|
||||
$stack = [];
|
||||
$stack = [];
|
||||
|
||||
/*
|
||||
We start to decode the response here. The understood tokens are:
|
||||
@@ -177,18 +210,18 @@ class Imap
|
||||
while ($token[0] == '(') {
|
||||
array_push($stack, $tokens);
|
||||
$tokens = [];
|
||||
$token = substr($token, 1);
|
||||
$token = substr($token, 1);
|
||||
}
|
||||
if ($token[0] == '"') {
|
||||
if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
|
||||
$tokens[] = $matches[1];
|
||||
$line = substr($line, strlen($matches[0]));
|
||||
$line = substr($line, strlen($matches[0]));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($token[0] == '{') {
|
||||
$endPos = strpos($token, '}');
|
||||
$chars = substr($token, 1, $endPos - 1);
|
||||
$chars = substr($token, 1, $endPos - 1);
|
||||
if (is_numeric($chars)) {
|
||||
$token = '';
|
||||
while (strlen($token) < $chars) {
|
||||
@@ -196,43 +229,43 @@ class Imap
|
||||
}
|
||||
$line = '';
|
||||
if (strlen($token) > $chars) {
|
||||
$line = substr($token, $chars);
|
||||
$line = substr($token, $chars);
|
||||
$token = substr($token, 0, $chars);
|
||||
} else {
|
||||
$line .= $this->nextLine();
|
||||
}
|
||||
$tokens[] = $token;
|
||||
$line = trim($line) . ' ';
|
||||
$line = trim($line) . ' ';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($stack && $token[strlen($token) - 1] == ')') {
|
||||
// closing braces are not separated by spaces, so we need to count them
|
||||
$braces = strlen($token);
|
||||
$token = rtrim($token, ')');
|
||||
$token = rtrim($token, ')');
|
||||
// only count braces if more than one
|
||||
$braces -= strlen($token) + 1;
|
||||
// only add if token had more than just closing braces
|
||||
if (rtrim($token) != '') {
|
||||
$tokens[] = rtrim($token);
|
||||
}
|
||||
$token = $tokens;
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
// special handline if more than one closing brace
|
||||
while ($braces-- > 0) {
|
||||
$tokens[] = $token;
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
}
|
||||
}
|
||||
$tokens[] = $token;
|
||||
$line = substr($line, $pos + 1);
|
||||
$line = substr($line, $pos + 1);
|
||||
}
|
||||
|
||||
// maybe the server forgot to send some closing braces
|
||||
while ($stack) {
|
||||
$child = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$child = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$tokens[] = $child;
|
||||
}
|
||||
|
||||
@@ -274,7 +307,7 @@ class Imap
|
||||
*/
|
||||
public function readResponse($tag, $dontParse = false)
|
||||
{
|
||||
$lines = [];
|
||||
$lines = [];
|
||||
$tokens = null; // define $tokens variable before first use
|
||||
while (! $this->readLine($tokens, $tag, $dontParse)) {
|
||||
$lines[] = $tokens;
|
||||
@@ -287,7 +320,7 @@ class Imap
|
||||
|
||||
// last line has response code
|
||||
if ($tokens[0] == 'OK') {
|
||||
return $lines ? $lines : true;
|
||||
return $lines ?: true;
|
||||
} elseif ($tokens[0] == 'NO') {
|
||||
return false;
|
||||
}
|
||||
@@ -341,9 +374,7 @@ class Imap
|
||||
{
|
||||
$tag = null; // define $tag variable before first use
|
||||
$this->sendRequest($command, $tokens, $tag);
|
||||
$response = $this->readResponse($tag, $dontParse);
|
||||
|
||||
return $response;
|
||||
return $this->readResponse($tag, $dontParse);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +387,7 @@ class Imap
|
||||
public function escapeString($string)
|
||||
{
|
||||
if (func_num_args() < 2) {
|
||||
if (strpos($string, "\n") !== false) {
|
||||
if (str_contains($string, "\n")) {
|
||||
return ['{' . strlen($string) . '}', $string];
|
||||
}
|
||||
|
||||
@@ -412,7 +443,7 @@ class Imap
|
||||
if ($this->socket) {
|
||||
try {
|
||||
$result = $this->requestAndResponse('LOGOUT', [], true);
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignoring exception
|
||||
}
|
||||
fclose($this->socket);
|
||||
@@ -425,7 +456,7 @@ class Imap
|
||||
* Get capabilities from IMAP server
|
||||
*
|
||||
* @return array list of capabilities
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function capability()
|
||||
{
|
||||
@@ -450,7 +481,7 @@ class Imap
|
||||
* @param string $box which folder to change to or examine
|
||||
* @return bool|array false if error, array with returned information
|
||||
* otherwise (flags, exists, recent, uidvalidity)
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
|
||||
{
|
||||
@@ -489,7 +520,7 @@ class Imap
|
||||
*
|
||||
* @param string $box change to this folder
|
||||
* @return bool|array see examineOrselect()
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function select($box = 'INBOX')
|
||||
{
|
||||
@@ -501,7 +532,7 @@ class Imap
|
||||
*
|
||||
* @param string $box examine this folder
|
||||
* @return bool|array see examineOrselect()
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function examine($box = 'INBOX')
|
||||
{
|
||||
@@ -535,7 +566,7 @@ class Imap
|
||||
$set = (int) $from . ':' . (int) $to;
|
||||
}
|
||||
|
||||
$items = (array) $items;
|
||||
$items = (array) $items;
|
||||
$itemList = $this->escapeList($items);
|
||||
|
||||
$tag = null; // define $tag variable before first use
|
||||
@@ -593,6 +624,7 @@ class Imap
|
||||
// if we want only one message we can ignore everything else and just return
|
||||
if ($to === null && ! is_array($from) && ($uid ? $tokens[2][$uidKey] == $from : $tokens[0] == $from)) {
|
||||
// we still need to read all lines
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedWhile
|
||||
while (! $this->readLine($tokens, $tag)) {
|
||||
}
|
||||
return $data;
|
||||
@@ -615,12 +647,12 @@ class Imap
|
||||
* @param string $reference mailbox reference for list
|
||||
* @param string $mailbox mailbox name match with wildcards
|
||||
* @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function listMailbox($reference = '', $mailbox = '*')
|
||||
{
|
||||
$result = [];
|
||||
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
|
||||
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
|
||||
if (! $list || $list === true) {
|
||||
return $result;
|
||||
}
|
||||
@@ -645,7 +677,7 @@ class Imap
|
||||
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
|
||||
* @param bool $silent if false the return values are the new flags for the wanted messages
|
||||
* @return bool|array new flags if $silent is false, else true or false depending on success
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
|
||||
{
|
||||
@@ -658,7 +690,7 @@ class Imap
|
||||
}
|
||||
|
||||
$flags = $this->escapeList($flags);
|
||||
$set = (int) $from;
|
||||
$set = (int) $from;
|
||||
if ($to !== null) {
|
||||
$set .= ':' . ($to == INF ? '*' : (int) $to);
|
||||
}
|
||||
@@ -689,11 +721,11 @@ class Imap
|
||||
* @param array $flags flags for new message
|
||||
* @param string $date date for new message
|
||||
* @return bool success
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function append($folder, $message, $flags = null, $date = null)
|
||||
{
|
||||
$tokens = [];
|
||||
$tokens = [];
|
||||
$tokens[] = $this->escapeString($folder);
|
||||
if ($flags !== null) {
|
||||
$tokens[] = $this->escapeList($flags);
|
||||
@@ -710,14 +742,14 @@ class Imap
|
||||
* copy message set from current folder to other folder
|
||||
*
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @return bool success
|
||||
*/
|
||||
public function copy($folder, $from, $to = null)
|
||||
{
|
||||
$set = (int) $from;
|
||||
$set = (string) $from;
|
||||
if ($to !== null) {
|
||||
$set .= ':' . ($to == INF ? '*' : (int) $to);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,23 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Mail\Protocol\Pop3\Response;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fwrite;
|
||||
use function is_string;
|
||||
use function md5;
|
||||
use function rtrim;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strpos;
|
||||
use function strtok;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
class Pop3
|
||||
{
|
||||
use ProtocolTrait;
|
||||
@@ -15,17 +30,17 @@ class Pop3
|
||||
|
||||
/**
|
||||
* saves if server supports top
|
||||
*
|
||||
* @var null|bool
|
||||
*/
|
||||
public $hasTop = null;
|
||||
public $hasTop;
|
||||
|
||||
/**
|
||||
* @var null|resource
|
||||
*/
|
||||
/** @var null|resource */
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* greeting timestamp for apop
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $timestamp;
|
||||
@@ -67,7 +82,7 @@ class Pop3
|
||||
public function connect($host, $port = null, $ssl = false)
|
||||
{
|
||||
$transport = 'tcp';
|
||||
$isTls = false;
|
||||
$isTls = false;
|
||||
|
||||
if ($ssl) {
|
||||
$ssl = strtolower($ssl);
|
||||
@@ -136,6 +151,37 @@ class Pop3
|
||||
* @return string response
|
||||
*/
|
||||
public function readResponse($multiline = false)
|
||||
{
|
||||
$response = $this->readRemoteResponse();
|
||||
|
||||
if ($response->status() != '+OK') {
|
||||
throw new Exception\RuntimeException('last request failed');
|
||||
}
|
||||
|
||||
$message = $response->message();
|
||||
|
||||
if ($multiline) {
|
||||
$message = '';
|
||||
$line = fgets($this->socket);
|
||||
while ($line && rtrim($line, "\r\n") != '.') {
|
||||
if ($line[0] == '.') {
|
||||
$line = substr($line, 1);
|
||||
}
|
||||
$message .= $line;
|
||||
$line = fgets($this->socket);
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a response
|
||||
* return extracted status / message from response
|
||||
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
protected function readRemoteResponse(): Response
|
||||
{
|
||||
ErrorHandler::start();
|
||||
$result = fgets($this->socket);
|
||||
@@ -146,29 +192,13 @@ class Pop3
|
||||
|
||||
$result = trim($result);
|
||||
if (strpos($result, ' ')) {
|
||||
list($status, $message) = explode(' ', $result, 2);
|
||||
[$status, $message] = explode(' ', $result, 2);
|
||||
} else {
|
||||
$status = $result;
|
||||
$status = $result;
|
||||
$message = '';
|
||||
}
|
||||
|
||||
if ($status != '+OK') {
|
||||
throw new Exception\RuntimeException('last request failed');
|
||||
}
|
||||
|
||||
if ($multiline) {
|
||||
$message = '';
|
||||
$line = fgets($this->socket);
|
||||
while ($line && rtrim($line, "\r\n") != '.') {
|
||||
if ($line[0] == '.') {
|
||||
$line = substr($line, 1);
|
||||
}
|
||||
$message .= $line;
|
||||
$line = fgets($this->socket);
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
return new Response($status, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,6 +206,7 @@ class Pop3
|
||||
*
|
||||
* @see sendRequest()
|
||||
* @see readResponse()
|
||||
*
|
||||
* @param string $request request
|
||||
* @param bool $multiline multiline response?
|
||||
* @return string result from readResponse()
|
||||
@@ -194,7 +225,7 @@ class Pop3
|
||||
if ($this->socket) {
|
||||
try {
|
||||
$this->request('QUIT');
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignore error - we're closing the socket anyway
|
||||
}
|
||||
|
||||
@@ -227,7 +258,7 @@ class Pop3
|
||||
try {
|
||||
$this->request("APOP $user " . md5($this->timestamp . $password));
|
||||
return;
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@@ -245,10 +276,10 @@ class Pop3
|
||||
public function status(&$messages, &$octets)
|
||||
{
|
||||
$messages = 0;
|
||||
$octets = 0;
|
||||
$result = $this->request('STAT');
|
||||
$octets = 0;
|
||||
$result = $this->request('STAT');
|
||||
|
||||
list($messages, $octets) = explode(' ', $result);
|
||||
[$messages, $octets] = explode(' ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,17 +293,17 @@ class Pop3
|
||||
if ($msgno !== null) {
|
||||
$result = $this->request("LIST $msgno");
|
||||
|
||||
list(, $result) = explode(' ', $result);
|
||||
[, $result] = explode(' ', $result);
|
||||
return (int) $result;
|
||||
}
|
||||
|
||||
$result = $this->request('LIST', true);
|
||||
$result = $this->request('LIST', true);
|
||||
$messages = [];
|
||||
$line = strtok($result, "\n");
|
||||
$line = strtok($result, "\n");
|
||||
while ($line) {
|
||||
list($no, $size) = explode(' ', trim($line));
|
||||
[$no, $size] = explode(' ', trim($line));
|
||||
$messages[(int) $no] = (int) $size;
|
||||
$line = strtok("\n");
|
||||
$line = strtok("\n");
|
||||
}
|
||||
|
||||
return $messages;
|
||||
@@ -289,19 +320,19 @@ class Pop3
|
||||
if ($msgno !== null) {
|
||||
$result = $this->request("UIDL $msgno");
|
||||
|
||||
list(, $result) = explode(' ', $result);
|
||||
[, $result] = explode(' ', $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = $this->request('UIDL', true);
|
||||
|
||||
$result = explode("\n", $result);
|
||||
$result = explode("\n", $result);
|
||||
$messages = [];
|
||||
foreach ($result as $line) {
|
||||
if (! $line) {
|
||||
continue;
|
||||
}
|
||||
list($no, $id) = explode(' ', trim($line), 2);
|
||||
[$no, $id] = explode(' ', trim($line), 2);
|
||||
$messages[(int) $no] = $id;
|
||||
}
|
||||
|
||||
@@ -333,7 +364,7 @@ class Pop3
|
||||
}
|
||||
$this->hasTop = true;
|
||||
|
||||
$lines = (! $lines || $lines < 1) ? 0 : (int) $lines;
|
||||
$lines = ! $lines || $lines < 1 ? 0 : (int) $lines;
|
||||
|
||||
try {
|
||||
$result = $this->request("TOP $msgno $lines", true);
|
||||
@@ -357,8 +388,7 @@ class Pop3
|
||||
*/
|
||||
public function retrieve($msgno)
|
||||
{
|
||||
$result = $this->request("RETR $msgno", true);
|
||||
return $result;
|
||||
return $this->request("RETR $msgno", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,7 +402,7 @@ class Pop3
|
||||
/**
|
||||
* Make a DELE count to remove a message
|
||||
*
|
||||
* @param $msgno
|
||||
* @param int $msgno
|
||||
*/
|
||||
public function delete($msgno)
|
||||
{
|
||||
|
||||
35
lib/laminas/laminas-mail/src/Protocol/Pop3/Response.php
Normal file
35
lib/laminas/laminas-mail/src/Protocol/Pop3/Response.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Protocol\Pop3;
|
||||
|
||||
/**
|
||||
* POP3 response value object
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Response
|
||||
{
|
||||
/** @var string $status */
|
||||
private $status;
|
||||
|
||||
/** @var string $message */
|
||||
private $message;
|
||||
|
||||
public function __construct(string $status, string $message)
|
||||
{
|
||||
$this->status = $status;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function status(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function message(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Laminas\Mail\Protocol\Pop3\Xoauth2;
|
||||
|
||||
use Laminas\Mail\Protocol\Exception\RuntimeException;
|
||||
use Laminas\Mail\Protocol\Pop3;
|
||||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class Microsoft extends Pop3
|
||||
{
|
||||
protected const AUTH_INITIALIZE_REQUEST = 'AUTH XOAUTH2';
|
||||
protected const AUTH_RESPONSE_INITIALIZED_OK = '+';
|
||||
|
||||
/**
|
||||
* @param string $user the target mailbox to access
|
||||
* @param string $password OAUTH2 accessToken
|
||||
* @param bool $tryApop obsolete parameter not used here
|
||||
*/
|
||||
public function login($user, $password, $tryApop = true): void
|
||||
{
|
||||
$this->sendRequest(self::AUTH_INITIALIZE_REQUEST);
|
||||
|
||||
$response = $this->readRemoteResponse();
|
||||
|
||||
if ($response->status() != self::AUTH_RESPONSE_INITIALIZED_OK) {
|
||||
throw new RuntimeException($response->message());
|
||||
}
|
||||
|
||||
$this->request(Xoauth2::encodeXoauth2Sasl($user, $password));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,17 @@ namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function defined;
|
||||
use function sprintf;
|
||||
use function stream_context_create;
|
||||
use function stream_set_timeout;
|
||||
use function stream_socket_client;
|
||||
|
||||
use const STREAM_CLIENT_CONNECT;
|
||||
use const STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
use const STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
|
||||
use const STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
|
||||
|
||||
/**
|
||||
* https://bugs.php.net/bug.php?id=69195
|
||||
*/
|
||||
@@ -11,6 +22,7 @@ trait ProtocolTrait
|
||||
{
|
||||
/**
|
||||
* If set to true, do not validate the SSL certificate
|
||||
*
|
||||
* @var null|bool
|
||||
*/
|
||||
protected $novalidatecert;
|
||||
@@ -45,8 +57,6 @@ trait ProtocolTrait
|
||||
|
||||
/**
|
||||
* Should we validate SSL certificate?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCert(): bool
|
||||
{
|
||||
@@ -94,7 +104,7 @@ trait ProtocolTrait
|
||||
STREAM_CLIENT_CONNECT,
|
||||
stream_context_create($this->prepareSocketOptions())
|
||||
);
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
|
||||
if (! $socket) {
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
|
||||
@@ -5,6 +5,23 @@ namespace Laminas\Mail\Protocol;
|
||||
use Generator;
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_replace_recursive;
|
||||
use function chunk_split;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function is_array;
|
||||
use function rewind;
|
||||
use function rtrim;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* SMTP implementation of Laminas\Mail\Protocol\AbstractProtocol
|
||||
*
|
||||
@@ -18,6 +35,7 @@ class Smtp extends AbstractProtocol
|
||||
/**
|
||||
* RFC 5322 section-2.2.3 specifies maximum of 998 bytes per line.
|
||||
* This may not be exceeded.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-2.2.3
|
||||
*/
|
||||
public const SMTP_LINE_LIMIT = 998;
|
||||
@@ -69,7 +87,7 @@ class Smtp extends AbstractProtocol
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $data = null;
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Whether or not send QUIT command
|
||||
@@ -79,8 +97,6 @@ class Smtp extends AbstractProtocol
|
||||
protected $useCompleteQuit = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The first argument may be an array of all options. If so, it must include
|
||||
* the 'host' and 'port' keys in order to ensure that all required values
|
||||
* are present.
|
||||
@@ -90,7 +106,7 @@ class Smtp extends AbstractProtocol
|
||||
* @param null|array $config
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null, array $config = null)
|
||||
public function __construct($host = '127.0.0.1', $port = null, ?array $config = null)
|
||||
{
|
||||
// Did we receive a configuration array?
|
||||
if (is_array($host)) {
|
||||
@@ -129,7 +145,7 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
case 'ssl':
|
||||
$this->transport = 'ssl';
|
||||
$this->secure = 'ssl';
|
||||
$this->secure = 'ssl';
|
||||
if ($port === null) {
|
||||
$port = 465;
|
||||
}
|
||||
@@ -177,10 +193,7 @@ class Smtp extends AbstractProtocol
|
||||
/**
|
||||
* Read $data as lines terminated by "\n"
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $chunkSize
|
||||
* @return Generator|string[]
|
||||
* @author Elan Ruusamäe <glen@pld-linux.org>
|
||||
*/
|
||||
private static function chunkedReader(string $data, int $chunkSize = 4096): Generator
|
||||
{
|
||||
@@ -305,7 +318,7 @@ class Smtp extends AbstractProtocol
|
||||
* Send EHLO or HELO depending on capabilities of smtp host
|
||||
*
|
||||
* @param string $host The client hostname or IP address (default: 127.0.0.1)
|
||||
* @throws \Exception|Exception\ExceptionInterface
|
||||
* @throws Exception\ExceptionInterface
|
||||
*/
|
||||
protected function ehlo($host)
|
||||
{
|
||||
@@ -313,7 +326,7 @@ class Smtp extends AbstractProtocol
|
||||
try {
|
||||
$this->_send('EHLO ' . $host);
|
||||
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
$this->_send('HELO ' . $host);
|
||||
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
|
||||
}
|
||||
@@ -388,7 +401,7 @@ class Smtp extends AbstractProtocol
|
||||
// Add "-1" to stay within limits,
|
||||
// because Headers::FOLDING includes a byte for space character after \r\n
|
||||
$chunks = chunk_split($line, self::SMTP_LINE_LIMIT - 1, Headers::FOLDING);
|
||||
$line = substr($chunks, 0, -strlen(Headers::FOLDING));
|
||||
$line = substr($chunks, 0, -strlen(Headers::FOLDING));
|
||||
}
|
||||
|
||||
$this->_send($line);
|
||||
@@ -420,7 +433,6 @@ class Smtp extends AbstractProtocol
|
||||
* Issues the NOOP command end validates answer
|
||||
*
|
||||
* Not used by Laminas\Mail, could be used to keep a connection alive or check if it is still open.
|
||||
*
|
||||
*/
|
||||
public function noop()
|
||||
{
|
||||
@@ -443,7 +455,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Issues the QUIT command and clears the current session
|
||||
*
|
||||
*/
|
||||
public function quit()
|
||||
{
|
||||
@@ -475,7 +486,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Closes connection
|
||||
*
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
@@ -488,7 +498,6 @@ class Smtp extends AbstractProtocol
|
||||
// @codingStandardsIgnoreLine PSR2.Methods.MethodDeclaration.Underscore
|
||||
protected function _disconnect()
|
||||
{
|
||||
|
||||
// Make sure the session gets closed
|
||||
$this->quit();
|
||||
parent::_disconnect();
|
||||
@@ -496,7 +505,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Start mail session
|
||||
*
|
||||
*/
|
||||
protected function startSession()
|
||||
{
|
||||
@@ -505,7 +513,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Stop mail session
|
||||
*
|
||||
*/
|
||||
protected function stopSession()
|
||||
{
|
||||
|
||||
@@ -5,24 +5,23 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
use Laminas\Crypt\Hmac;
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_decode;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs CRAM-MD5 authentication
|
||||
*/
|
||||
class Crammd5 extends Smtp
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* All parameters may be passed as an array to the first argument of the
|
||||
* constructor. If so,
|
||||
*
|
||||
@@ -67,7 +66,7 @@ class Crammd5 extends Smtp
|
||||
$this->_send('AUTH CRAM-MD5');
|
||||
$challenge = $this->_expect(334);
|
||||
$challenge = base64_decode($challenge);
|
||||
$digest = $this->hmacMd5($this->getPassword(), $challenge);
|
||||
$digest = $this->hmacMd5($this->getPassword(), $challenge);
|
||||
$this->_send(base64_encode($this->getUsername() . ' ' . $digest));
|
||||
$this->_expect(235);
|
||||
$this->auth = true;
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs LOGIN authentication
|
||||
*/
|
||||
@@ -24,8 +28,6 @@ class Login extends Smtp
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host (Default: 127.0.0.1)
|
||||
* @param int $port (Default: null)
|
||||
* @param array $config Auth-specific parameters
|
||||
@@ -58,7 +60,6 @@ class Login extends Smtp
|
||||
|
||||
/**
|
||||
* Perform LOGIN authentication with supplied credentials
|
||||
*
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs PLAIN authentication
|
||||
*/
|
||||
@@ -24,8 +28,6 @@ class Plain extends Smtp
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host (Default: 127.0.0.1)
|
||||
* @param int $port (Default: null)
|
||||
* @param array $config Auth-specific parameters
|
||||
@@ -58,7 +60,6 @@ class Plain extends Smtp
|
||||
|
||||
/**
|
||||
* Perform PLAIN authentication with supplied credentials
|
||||
*
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
|
||||
123
lib/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php
Normal file
123
lib/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2 as Xoauth2AuthEncoder;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs Xoauth2 authentication
|
||||
*
|
||||
* @psalm-suppress PropertyNotSetInConstructor
|
||||
*/
|
||||
final class Xoauth2 extends Smtp
|
||||
{
|
||||
/**
|
||||
* SMTP username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* Xoauth2 access token
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @param string|array $host (Default: 127.0.0.1)
|
||||
* @param int|null $port (Default: null)
|
||||
* @param array|null $config Auth-specific parameters
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null, ?array $config = null)
|
||||
{
|
||||
// Did we receive a configuration array?
|
||||
$origConfig = $config;
|
||||
if (is_array($host)) {
|
||||
// Merge config array with principal array, if provided
|
||||
if (is_array($config)) {
|
||||
$config = array_replace_recursive($host, $config);
|
||||
} else {
|
||||
$config = $host;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($config)) {
|
||||
if (isset($config['username'])) {
|
||||
$this->setUsername((string) $config['username']);
|
||||
}
|
||||
if (isset($config['access_token'])) {
|
||||
$this->setAccessToken((string) $config['access_token']);
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent with original arguments
|
||||
parent::__construct($host, $port, $origConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform XOAUTH2 authentication with supplied credentials
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
// Ensure AUTH has not already been initiated.
|
||||
parent::auth();
|
||||
|
||||
$this->_send('AUTH XOAUTH2');
|
||||
$this->_expect('334');
|
||||
$this->_send(Xoauth2AuthEncoder::encodeXoauth2Sasl($this->getUsername(), $this->getAccessToken()));
|
||||
$this->_expect('235');
|
||||
$this->auth = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value for username
|
||||
*
|
||||
* @param string $username
|
||||
* @return Xoauth2
|
||||
*/
|
||||
public function setUsername($username)
|
||||
{
|
||||
$this->username = $username;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get username
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value for access token
|
||||
*
|
||||
* @param string $token
|
||||
* @return Xoauth2
|
||||
*/
|
||||
public function setAccessToken($token)
|
||||
{
|
||||
$this->accessToken = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,33 @@
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\ServiceManager\AbstractPluginManager;
|
||||
use Laminas\ServiceManager\ConfigInterface;
|
||||
use Laminas\ServiceManager\Exception\InvalidServiceException;
|
||||
use Laminas\ServiceManager\Factory\InvokableFactory;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Plugin manager implementation for SMTP extensions.
|
||||
*
|
||||
* Enforces that SMTP extensions retrieved are instances of Smtp. Additionally,
|
||||
* it registers a number of default extensions available.
|
||||
*
|
||||
* @link ConfigInterface
|
||||
*
|
||||
* @psalm-import-type FactoriesConfigurationType from ConfigInterface
|
||||
*
|
||||
* @extends AbstractPluginManager<Smtp>
|
||||
* @final
|
||||
*/
|
||||
class SmtpPluginManager extends AbstractPluginManager
|
||||
{
|
||||
/**
|
||||
* Service aliases
|
||||
*
|
||||
* @var array<array-key, class-string>
|
||||
*/
|
||||
protected $aliases = [
|
||||
'crammd5' => Smtp\Auth\Crammd5::class,
|
||||
@@ -27,61 +41,58 @@ class SmtpPluginManager extends AbstractPluginManager
|
||||
'Login' => Smtp\Auth\Login::class,
|
||||
'plain' => Smtp\Auth\Plain::class,
|
||||
'Plain' => Smtp\Auth\Plain::class,
|
||||
'xoauth2' => Smtp\Auth\Xoauth2::class,
|
||||
'Xoauth2' => Smtp\Auth\Xoauth2::class,
|
||||
'smtp' => Smtp::class,
|
||||
'Smtp' => Smtp::class,
|
||||
'SMTP' => Smtp::class,
|
||||
|
||||
// Legacy Zend Framework aliases
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Crammd5::class => Smtp\Auth\Crammd5::class,
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Login::class => Smtp\Auth\Login::class,
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Plain::class => Smtp\Auth\Plain::class,
|
||||
\Zend\Mail\Protocol\Smtp::class => Smtp::class,
|
||||
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Crammd5' => Smtp\Auth\Crammd5::class,
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Login' => Smtp\Auth\Login::class,
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Plain' => Smtp\Auth\Plain::class,
|
||||
'Zend\Mail\Protocol\Smtp' => Smtp::class,
|
||||
// v2 normalized FQCNs
|
||||
'zendmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'zendmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'zendmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'zendmailprotocolsmtp' => Smtp::class,
|
||||
'zendmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'zendmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'zendmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'zendmailprotocolsmtp' => Smtp::class,
|
||||
'laminasmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'laminasmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'laminasmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'laminasmailprotocolsmtp' => Smtp::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Service factories
|
||||
*
|
||||
* @var array
|
||||
* @var FactoriesConfigurationType
|
||||
*/
|
||||
protected $factories = [
|
||||
Smtp\Auth\Crammd5::class => InvokableFactory::class,
|
||||
Smtp\Auth\Login::class => InvokableFactory::class,
|
||||
Smtp\Auth\Plain::class => InvokableFactory::class,
|
||||
Smtp\Auth\Xoauth2::class => InvokableFactory::class,
|
||||
Smtp::class => InvokableFactory::class,
|
||||
|
||||
// v2 normalized service names
|
||||
|
||||
'laminasmailprotocolsmtpauthcrammd5' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtpauthlogin' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtpauthplain' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtp' => InvokableFactory::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Plugins must be an instance of the Smtp class
|
||||
*
|
||||
* @var string
|
||||
* @var class-string<Smtp>
|
||||
*/
|
||||
protected $instanceOf = Smtp::class;
|
||||
|
||||
/**
|
||||
* Validate a retrieved plugin instance (v3).
|
||||
*
|
||||
* @param object|array $instance
|
||||
* @throws InvalidServiceException
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($instance)
|
||||
public function validate(mixed $instance)
|
||||
{
|
||||
if (! $instance instanceof $this->instanceOf) {
|
||||
throw new InvalidServiceException(sprintf(
|
||||
'Plugin of type %s is invalid; must extend %s',
|
||||
(is_object($instance) ? get_class($instance) : gettype($instance)),
|
||||
is_object($instance) ? $instance::class : gettype($instance),
|
||||
$this->instanceOf
|
||||
));
|
||||
}
|
||||
@@ -90,10 +101,12 @@ class SmtpPluginManager extends AbstractPluginManager
|
||||
/**
|
||||
* Validate a retrieved plugin instance (v2).
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param object $plugin
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function validatePlugin($plugin)
|
||||
public function validatePlugin(mixed $plugin)
|
||||
{
|
||||
try {
|
||||
$this->validate($plugin);
|
||||
|
||||
@@ -2,25 +2,34 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
// phpcs:ignore WebimpressCodingStandard.PHP.CorrectClassNameCase.Invalid
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Laminas\ServiceManager\FactoryInterface;
|
||||
use Laminas\ServiceManager\ServiceLocatorInterface;
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
|
||||
/**
|
||||
* @link ServiceManager
|
||||
*
|
||||
* @psalm-import-type ServiceManagerConfiguration from ServiceManager
|
||||
*/
|
||||
class SmtpPluginManagerFactory implements FactoryInterface
|
||||
{
|
||||
/**
|
||||
* laminas-servicemanager v2 support for invocation options.
|
||||
*
|
||||
* @param array
|
||||
* @var array
|
||||
* @psalm-var ServiceManagerConfiguration
|
||||
*/
|
||||
protected $creationOptions;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param ServiceManagerConfiguration $options
|
||||
* @return SmtpPluginManager
|
||||
*/
|
||||
public function __invoke(ContainerInterface $container, $name, array $options = null)
|
||||
public function __invoke(ContainerInterface $container, $name, ?array $options = null)
|
||||
{
|
||||
return new SmtpPluginManager($container, $options ?: []);
|
||||
}
|
||||
@@ -38,7 +47,7 @@ class SmtpPluginManagerFactory implements FactoryInterface
|
||||
/**
|
||||
* laminas-servicemanager v2 support for invocation options.
|
||||
*
|
||||
* @param array $options
|
||||
* @psalm-param ServiceManagerConfiguration $options
|
||||
* @return void
|
||||
*/
|
||||
public function setCreationOptions(array $options)
|
||||
|
||||
32
lib/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php
Normal file
32
lib/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Protocol\Xoauth2;
|
||||
|
||||
use function base64_encode;
|
||||
use function chr;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Xoauth2
|
||||
{
|
||||
/**
|
||||
* encodes accessToken and target mailbox to Xoauth2 SASL base64 encoded string
|
||||
*/
|
||||
public static function encodeXoauth2Sasl(string $targetMailbox, string $accessToken): string
|
||||
{
|
||||
return base64_encode(
|
||||
sprintf(
|
||||
"user=%s%sauth=Bearer %s%s%s",
|
||||
$targetMailbox,
|
||||
chr(0x01),
|
||||
$accessToken,
|
||||
chr(0x01),
|
||||
chr(0x01)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,14 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use Laminas\Mail\Storage\Message;
|
||||
use ReturnTypeWillChange;
|
||||
use SeekableIterator;
|
||||
|
||||
use function str_starts_with;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
abstract class AbstractStorage implements
|
||||
ArrayAccess,
|
||||
Countable,
|
||||
@@ -14,6 +19,7 @@ abstract class AbstractStorage implements
|
||||
{
|
||||
/**
|
||||
* class capabilities with default values
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $has = [
|
||||
@@ -27,19 +33,22 @@ abstract class AbstractStorage implements
|
||||
|
||||
/**
|
||||
* current iteration position
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $iterationPos = 0;
|
||||
|
||||
/**
|
||||
* maximum iteration position (= message count)
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $iterationMax = null;
|
||||
protected $iterationMax;
|
||||
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<Message\MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message::class;
|
||||
|
||||
@@ -54,13 +63,13 @@ abstract class AbstractStorage implements
|
||||
*
|
||||
* @param string $var property name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return bool supported or not
|
||||
* @return null|bool supported or not
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
if (strpos($var, 'has') === 0) {
|
||||
if (str_starts_with($var, 'has')) {
|
||||
$var = strtolower(substr($var, 3));
|
||||
return isset($this->has[$var]) ? $this->has[$var] : null;
|
||||
return $this->has[$var] ?? null;
|
||||
}
|
||||
|
||||
throw new Exception\InvalidArgumentException($var . ' not found');
|
||||
@@ -95,8 +104,8 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* Get a message with headers and body
|
||||
*
|
||||
* @param $id int number of message
|
||||
* @return Message
|
||||
* @param int $id number of message
|
||||
* @return Message\MessageInterface
|
||||
*/
|
||||
abstract public function getMessage($id);
|
||||
|
||||
@@ -149,7 +158,7 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* delete a message from current box/folder
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id message number
|
||||
*/
|
||||
abstract public function removeMessage($id);
|
||||
|
||||
@@ -202,7 +211,7 @@ abstract class AbstractStorage implements
|
||||
if ($this->getMessage($id)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -212,7 +221,7 @@ abstract class AbstractStorage implements
|
||||
* ArrayAccess::offsetGet()
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Laminas\Mail\Storage\Message message object
|
||||
* @return Message message object
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetGet($id)
|
||||
@@ -223,12 +232,10 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* ArrayAccess::offsetSet()
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param mixed $value
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet($id, $value)
|
||||
public function offsetSet(mixed $id, mixed $value)
|
||||
{
|
||||
throw new Exception\RuntimeException('cannot write mail messages via array access');
|
||||
}
|
||||
|
||||
@@ -4,48 +4,39 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use RecursiveIterator;
|
||||
use ReturnTypeWillChange;
|
||||
use Stringable;
|
||||
|
||||
class Folder implements RecursiveIterator
|
||||
use function current;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
|
||||
class Folder implements RecursiveIterator, Stringable
|
||||
{
|
||||
/**
|
||||
* subfolders of folder array(localName => \Laminas\Mail\Storage\Folder folder)
|
||||
* @var array
|
||||
*/
|
||||
protected $folders;
|
||||
|
||||
/**
|
||||
* local name (name of folder in parent folder)
|
||||
* @var string
|
||||
*/
|
||||
protected $localName;
|
||||
|
||||
/**
|
||||
* global name (absolute name of folder)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $globalName;
|
||||
|
||||
/**
|
||||
* folder is selectable if folder is able to hold messages, otherwise it is a parent folder
|
||||
* @var bool
|
||||
*/
|
||||
protected $selectable = true;
|
||||
|
||||
/**
|
||||
* create a new mail folder instance
|
||||
*
|
||||
* @param string $localName name of folder in current subdirectory
|
||||
* @param string $localName local name (name of folder in parent folder)
|
||||
* @param string $globalName absolute name of folder
|
||||
* @param bool $selectable if true folder holds messages, if false it's
|
||||
* just a parent for subfolders (Default: true)
|
||||
* @param array $folders init with given instances of Folder as subfolders
|
||||
* @param array<string, Folder> $folders subfolders of
|
||||
* folder array(localName => \Laminas\Mail\Storage\Folder folder)
|
||||
*/
|
||||
public function __construct($localName, $globalName = '', $selectable = true, array $folders = [])
|
||||
{
|
||||
$this->localName = $localName;
|
||||
$this->globalName = $globalName ? $globalName : $localName;
|
||||
$this->selectable = $selectable;
|
||||
$this->folders = $folders;
|
||||
public function __construct(
|
||||
protected $localName,
|
||||
$globalName = '',
|
||||
protected $selectable = true,
|
||||
protected array $folders = []
|
||||
) {
|
||||
$this->globalName = $globalName ?: $localName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +54,7 @@ class Folder implements RecursiveIterator
|
||||
/**
|
||||
* implements RecursiveIterator::getChildren()
|
||||
*
|
||||
* @return \Laminas\Mail\Storage\Folder same as self::current()
|
||||
* @return Folder same as self::current()
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getChildren()
|
||||
@@ -105,7 +96,7 @@ class Folder implements RecursiveIterator
|
||||
/**
|
||||
* implements Iterator::current()
|
||||
*
|
||||
* @return \Laminas\Mail\Storage\Folder current folder
|
||||
* @return Folder current folder
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -127,7 +118,7 @@ class Folder implements RecursiveIterator
|
||||
*
|
||||
* @param string $name wanted subfolder
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return \Laminas\Mail\Storage\Folder folder named $folder
|
||||
* @return Folder folder named $folder
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
@@ -142,7 +133,7 @@ class Folder implements RecursiveIterator
|
||||
* add or replace subfolder named $name
|
||||
*
|
||||
* @param string $name local name of subfolder
|
||||
* @param \Laminas\Mail\Storage\Folder $folder instance for new subfolder
|
||||
* @param Folder $folder instance for new subfolder
|
||||
*/
|
||||
public function __set($name, self $folder)
|
||||
{
|
||||
@@ -164,7 +155,7 @@ class Folder implements RecursiveIterator
|
||||
*
|
||||
* @return string global name of folder
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getGlobalName();
|
||||
}
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
|
||||
namespace Laminas\Mail\Storage\Folder;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
|
||||
interface FolderInterface
|
||||
{
|
||||
/**
|
||||
* get root folder or given folder
|
||||
*
|
||||
* @param string $rootFolder get folder structure for given folder, else root
|
||||
* @return FolderInterface root or wanted folder
|
||||
* @return Folder root or wanted folder
|
||||
*/
|
||||
public function getFolders($rootFolder = null);
|
||||
|
||||
@@ -17,16 +20,16 @@ interface FolderInterface
|
||||
*
|
||||
* folder must be selectable!
|
||||
*
|
||||
* @param FolderInterface|string $globalName global name of folder or instance for subfolder
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @param Folder|string $globalName global name of folder or instance for subfolder
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function selectFolder($globalName);
|
||||
|
||||
/**
|
||||
* get Laminas\Mail\Storage\Folder instance for current folder
|
||||
*
|
||||
* @return FolderInterface instance of current folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return string instance of current folder
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getCurrentFolder();
|
||||
}
|
||||
|
||||
@@ -4,31 +4,55 @@ namespace Laminas\Mail\Storage\Folder;
|
||||
|
||||
use Laminas\Mail\Storage;
|
||||
use Laminas\Mail\Storage\Exception;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
use Laminas\Mail\Storage\ParamsNormalizer;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function closedir;
|
||||
use function explode;
|
||||
use function is_dir;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function rtrim;
|
||||
use function sort;
|
||||
use function str_contains;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
|
||||
class Maildir extends Storage\Maildir implements FolderInterface
|
||||
{
|
||||
/**
|
||||
* root folder for folder structure
|
||||
*
|
||||
* @var Storage\Folder
|
||||
*/
|
||||
protected $rootFolder;
|
||||
|
||||
/**
|
||||
* rootdir of folder structure
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootdir;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder;
|
||||
|
||||
/**
|
||||
* delim char for subfolders
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $delim;
|
||||
@@ -42,7 +66,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
* - delim delim char for folder structure, default is '.'
|
||||
* - folder initial selected folder, default is 'INBOX'
|
||||
*
|
||||
* @param $params array mail reader specific parameters
|
||||
* @param object|array $params mail reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($params)
|
||||
@@ -61,14 +85,14 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
|
||||
$this->rootdir = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$delim = $params['delim'] ?? '.';
|
||||
$delim = $params['delim'] ?? '.';
|
||||
$this->delim = (string) $delim;
|
||||
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
|
||||
$this->buildFolderTree();
|
||||
$this->selectFolder((string) $folder);
|
||||
$this->has['top'] = true;
|
||||
$this->has['top'] = true;
|
||||
$this->has['flags'] = true;
|
||||
}
|
||||
|
||||
@@ -82,7 +106,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
*/
|
||||
protected function buildFolderTree()
|
||||
{
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$this->rootFolder->INBOX = new Storage\Folder('INBOX', 'INBOX', true);
|
||||
|
||||
ErrorHandler::start(E_WARNING);
|
||||
@@ -106,27 +130,27 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
closedir($dh);
|
||||
|
||||
sort($dirs);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$parentFolder = $this->rootFolder;
|
||||
$parent = '.';
|
||||
$parent = '.';
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
do {
|
||||
if (strpos($dir, $parent) === 0) {
|
||||
$local = substr($dir, strlen($parent));
|
||||
if (strpos($local, $this->delim) !== false) {
|
||||
if (str_starts_with($dir, $parent)) {
|
||||
$local = substr($dir, strlen((string) $parent));
|
||||
if (str_contains($local, $this->delim)) {
|
||||
throw new Exception\RuntimeException('error while reading maildir');
|
||||
}
|
||||
array_push($stack, $parent);
|
||||
$parent = $dir . $this->delim;
|
||||
$folder = new Storage\Folder($local, substr($dir, 1), true);
|
||||
$parent = $dir . $this->delim;
|
||||
$folder = new Storage\Folder($local, substr($dir, 1), true);
|
||||
$parentFolder->$local = $folder;
|
||||
array_push($folderStack, $parentFolder);
|
||||
$parentFolder = $folder;
|
||||
break;
|
||||
} elseif ($stack) {
|
||||
$parent = array_pop($stack);
|
||||
$parent = array_pop($stack);
|
||||
$parentFolder = array_pop($folderStack);
|
||||
}
|
||||
} while ($stack);
|
||||
@@ -140,8 +164,8 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
* get root folder or given folder
|
||||
*
|
||||
* @param string $rootFolder get folder structure for given folder, else root
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @return \Laminas\Mail\Storage\Folder root or wanted folder
|
||||
* @throws InvalidArgumentException
|
||||
* @return Folder root or wanted folder
|
||||
*/
|
||||
public function getFolders($rootFolder = null)
|
||||
{
|
||||
@@ -150,15 +174,15 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
}
|
||||
|
||||
// rootdir is same as INBOX in maildir
|
||||
if (strpos($rootFolder, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($rootFolder, 'INBOX' . $this->delim)) {
|
||||
$rootFolder = substr($rootFolder, 6);
|
||||
}
|
||||
$currentFolder = $this->rootFolder;
|
||||
$subname = trim($rootFolder, $this->delim);
|
||||
$subname = trim($rootFolder, $this->delim);
|
||||
|
||||
while ($currentFolder) {
|
||||
if (false !== strpos($subname, $this->delim)) {
|
||||
list($entry, $subname) = explode($this->delim, $subname, 2);
|
||||
if (str_contains($subname, $this->delim)) {
|
||||
[$entry, $subname] = explode($this->delim, $subname, 2);
|
||||
} else {
|
||||
$entry = $subname;
|
||||
$subname = null;
|
||||
@@ -214,7 +238,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
/**
|
||||
* get Storage\Folder instance for current folder
|
||||
*
|
||||
* @return Storage\Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
{
|
||||
|
||||
@@ -7,22 +7,40 @@ use Laminas\Mail\Storage\Exception;
|
||||
use Laminas\Mail\Storage\ParamsNormalizer;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_merge;
|
||||
use function closedir;
|
||||
use function explode;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function trim;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
|
||||
class Mbox extends Storage\Mbox implements FolderInterface
|
||||
{
|
||||
/**
|
||||
* Storage\Folder root folder for folder structure
|
||||
*
|
||||
* @var Storage\Folder
|
||||
*/
|
||||
protected $rootFolder;
|
||||
|
||||
/**
|
||||
* rootdir of folder structure
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootdir;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder;
|
||||
@@ -38,7 +56,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
* - dirname rootdir of mbox structure
|
||||
* - folder initial selected folder, default is 'INBOX'
|
||||
*
|
||||
* @param $params array|object Array, iterable object, or stdClass object
|
||||
* @param array|object $params Array, iterable object, or stdClass object
|
||||
* with reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
@@ -61,7 +79,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
}
|
||||
|
||||
$this->rootdir = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
|
||||
$this->buildFolderTree($this->rootdir);
|
||||
$this->selectFolder((string) $folder);
|
||||
@@ -84,7 +102,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
{
|
||||
if (! $parentFolder) {
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$parentFolder = $this->rootFolder;
|
||||
$parentFolder = $this->rootFolder;
|
||||
}
|
||||
|
||||
ErrorHandler::start(E_WARNING);
|
||||
@@ -99,15 +117,15 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
continue;
|
||||
}
|
||||
$absoluteEntry = $currentDir . $entry;
|
||||
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
|
||||
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
|
||||
if (is_file($absoluteEntry) && $this->isMboxFile($absoluteEntry)) {
|
||||
$parentFolder->$entry = new Storage\Folder($entry, $globalName);
|
||||
continue;
|
||||
}
|
||||
if (! is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
|
||||
if (! is_dir($absoluteEntry)) { /* || $entry == '.' || $entry == '..' */
|
||||
continue;
|
||||
}
|
||||
$folder = new Storage\Folder($entry, $globalName, false);
|
||||
$folder = new Storage\Folder($entry, $globalName, false);
|
||||
$parentFolder->$entry = $folder;
|
||||
$this->buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
|
||||
}
|
||||
@@ -129,10 +147,10 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
}
|
||||
|
||||
$currentFolder = $this->rootFolder;
|
||||
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
|
||||
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
|
||||
while ($currentFolder) {
|
||||
if (false !== strpos($subname, DIRECTORY_SEPARATOR)) {
|
||||
list($entry, $subname) = explode(DIRECTORY_SEPARATOR, $subname, 2);
|
||||
if (str_contains($subname, DIRECTORY_SEPARATOR)) {
|
||||
[$entry, $subname] = explode(DIRECTORY_SEPARATOR, $subname, 2);
|
||||
} else {
|
||||
$entry = $subname;
|
||||
$subname = null;
|
||||
@@ -188,7 +206,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
/**
|
||||
* get Storage\Folder instance for current folder
|
||||
*
|
||||
* @return Storage\Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
* @throws Exception\ExceptionInterface
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
|
||||
@@ -5,6 +5,20 @@ namespace Laminas\Mail\Storage;
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Protocol;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function ksort;
|
||||
use function str_starts_with;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
|
||||
use const INF;
|
||||
use const SORT_STRING;
|
||||
|
||||
class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\WritableInterface
|
||||
{
|
||||
// TODO: with an internal cache we could optimize this class, or create an extra class with
|
||||
@@ -12,24 +26,28 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
|
||||
/**
|
||||
* protocol handler
|
||||
*
|
||||
* @var null|Protocol\Imap
|
||||
*/
|
||||
protected $protocol;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder = '';
|
||||
|
||||
/**
|
||||
* IMAP folder delimiter character
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $delimiter;
|
||||
|
||||
/**
|
||||
* IMAP flags to constants translation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $knownFlags = [
|
||||
@@ -44,6 +62,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
|
||||
/**
|
||||
* IMAP flags to search criteria
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $searchFlags = [
|
||||
@@ -110,7 +129,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
|
||||
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
|
||||
$header = $data['RFC822.HEADER'];
|
||||
|
||||
$flags = [];
|
||||
@@ -121,13 +140,12 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message header
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws Exception\RuntimeException
|
||||
* @throws Protocol\Exception\RuntimeException
|
||||
@@ -143,7 +161,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
return $this->protocol->fetch('RFC822.HEADER', $id);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -331,16 +349,16 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
}
|
||||
|
||||
ksort($folders, SORT_STRING);
|
||||
$root = new Folder('/', '/', false);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$root = new Folder('/', '/', false);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$parentFolder = $root;
|
||||
$parent = '';
|
||||
$parent = '';
|
||||
|
||||
foreach ($folders as $globalName => $data) {
|
||||
do {
|
||||
if (! $parent || strpos($globalName, $parent) === 0) {
|
||||
$pos = strrpos($globalName, $data['delim']);
|
||||
if (! $parent || str_starts_with($globalName, ! is_string($parent) ? (string) $parent : $parent)) {
|
||||
$pos = strrpos($globalName, (string) $data['delim']);
|
||||
if ($pos === false) {
|
||||
$localName = $globalName;
|
||||
} else {
|
||||
@@ -349,15 +367,15 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
$selectable = ! $data['flags'] || ! in_array('\\Noselect', $data['flags']);
|
||||
|
||||
array_push($stack, $parent);
|
||||
$parent = $globalName . $data['delim'];
|
||||
$folder = new Folder($localName, $globalName, $selectable);
|
||||
$parent = $globalName . $data['delim'];
|
||||
$folder = new Folder($localName, $globalName, $selectable);
|
||||
$parentFolder->$localName = $folder;
|
||||
array_push($folderStack, $parentFolder);
|
||||
$parentFolder = $folder;
|
||||
$parentFolder = $folder;
|
||||
$this->delimiter = $data['delim'];
|
||||
break;
|
||||
} elseif ($stack) {
|
||||
$parent = array_pop($stack);
|
||||
$parent = array_pop($stack);
|
||||
$parentFolder = array_pop($folderStack);
|
||||
}
|
||||
} while ($stack);
|
||||
@@ -380,7 +398,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
*/
|
||||
public function selectFolder($globalName)
|
||||
{
|
||||
$this->currentFolder = $globalName;
|
||||
$this->currentFolder = (string) $globalName;
|
||||
if (! $this->protocol->select($this->currentFolder)) {
|
||||
$this->currentFolder = '';
|
||||
throw new Exception\RuntimeException('cannot change folder, maybe it does not exist');
|
||||
@@ -390,7 +408,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
/**
|
||||
* get Folder instance for current folder
|
||||
*
|
||||
* @return Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
{
|
||||
|
||||
@@ -3,18 +3,50 @@
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Message\File;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_flip;
|
||||
use function closedir;
|
||||
use function count;
|
||||
use function ctype_digit;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function feof;
|
||||
use function fgets;
|
||||
use function file_exists;
|
||||
use function filesize;
|
||||
use function fopen;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_subclass_of;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function strcmp;
|
||||
use function stream_get_contents;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use function usort;
|
||||
|
||||
use const E_WARNING;
|
||||
|
||||
class Maildir extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<Mail\Storage\Message\MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message\File::class;
|
||||
protected $messageClass = File::class;
|
||||
|
||||
/**
|
||||
* data of found message files in maildir dir
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $files = [];
|
||||
@@ -121,14 +153,15 @@ class Maildir extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message\File
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return File
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
// TODO that's ugly, would be better to let the message class decide
|
||||
if (\trim($this->messageClass, '\\') === Message\File::class
|
||||
|| is_subclass_of($this->messageClass, Message\File::class)
|
||||
if (
|
||||
trim($this->messageClass, '\\') === File::class
|
||||
|| is_subclass_of($this->messageClass, File::class)
|
||||
) {
|
||||
return new $this->messageClass([
|
||||
'file' => $this->getFileData($id, 'filename'),
|
||||
@@ -144,7 +177,7 @@ class Maildir extends AbstractStorage
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -175,7 +208,7 @@ class Maildir extends AbstractStorage
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -209,7 +242,7 @@ class Maildir extends AbstractStorage
|
||||
* Supported parameters are:
|
||||
* - dirname dirname of mbox file
|
||||
*
|
||||
* @param $params array|object Array, iterable object, or stdClass object
|
||||
* @param array|object $params Array, iterable object, or stdClass object
|
||||
* with reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
@@ -221,7 +254,7 @@ class Maildir extends AbstractStorage
|
||||
throw new Exception\InvalidArgumentException('no dirname provided in params');
|
||||
}
|
||||
|
||||
$dirname = (string) $params['dirname'] ;
|
||||
$dirname = (string) $params['dirname'];
|
||||
|
||||
if (! is_dir($dirname)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf('Maildir "%s" is not a directory', $dirname));
|
||||
@@ -231,7 +264,7 @@ class Maildir extends AbstractStorage
|
||||
throw new Exception\InvalidArgumentException('invalid maildir given');
|
||||
}
|
||||
|
||||
$this->has['top'] = true;
|
||||
$this->has['top'] = true;
|
||||
$this->has['flags'] = true;
|
||||
$this->openMaildir($dirname);
|
||||
}
|
||||
@@ -299,15 +332,15 @@ class Maildir extends AbstractStorage
|
||||
continue;
|
||||
}
|
||||
|
||||
if (false !== strpos($entry, ':')) {
|
||||
list($uniq, $info) = explode(':', $entry, 2);
|
||||
if (str_contains($entry, ':')) {
|
||||
[$uniq, $info] = explode(':', $entry, 2);
|
||||
} else {
|
||||
$uniq = $entry;
|
||||
$info = '';
|
||||
}
|
||||
|
||||
if (false !== strpos($uniq, ',')) {
|
||||
list(, $size) = explode(',', $uniq, 2);
|
||||
if (str_contains($uniq, ',')) {
|
||||
[, $size] = explode(',', $uniq, 2);
|
||||
} else {
|
||||
$size = '';
|
||||
}
|
||||
@@ -320,8 +353,8 @@ class Maildir extends AbstractStorage
|
||||
$size = null;
|
||||
}
|
||||
|
||||
if (false !== strpos($info, ',')) {
|
||||
list($version, $flags) = explode(',', $info, 2);
|
||||
if (str_contains($info, ',')) {
|
||||
[$version, $flags] = explode(',', $info, 2);
|
||||
} else {
|
||||
$version = $info;
|
||||
$flags = '';
|
||||
@@ -332,9 +365,9 @@ class Maildir extends AbstractStorage
|
||||
}
|
||||
|
||||
$namedFlags = $defaultFlags;
|
||||
$length = strlen($flags);
|
||||
$length = strlen($flags);
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$flag = $flags[$i];
|
||||
$flag = $flags[$i];
|
||||
$namedFlags[$flag] = static::$knownFlags[$flag] ?? $flag;
|
||||
}
|
||||
|
||||
@@ -350,15 +383,12 @@ class Maildir extends AbstractStorage
|
||||
$this->files[] = $data;
|
||||
}
|
||||
|
||||
\usort($this->files, function ($a, $b): int {
|
||||
return \strcmp($a['filename'], $b['filename']);
|
||||
});
|
||||
usort($this->files, static fn($a, $b): int => strcmp($a['filename'], $b['filename']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close resource for mail lib. If you need to control, when the resource
|
||||
* is closed. Otherwise the destructor would call this.
|
||||
*
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -378,7 +408,7 @@ class Maildir extends AbstractStorage
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
|
||||
@@ -2,52 +2,81 @@
|
||||
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Message\File;
|
||||
use Laminas\Mail\Storage\Message\MessageInterface;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_combine;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function filemtime;
|
||||
use function fopen;
|
||||
use function fseek;
|
||||
use function ftell;
|
||||
use function is_dir;
|
||||
use function is_resource;
|
||||
use function is_subclass_of;
|
||||
use function range;
|
||||
use function str_starts_with;
|
||||
use function stream_get_contents;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
use const E_WARNING;
|
||||
|
||||
class Mbox extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* file handle to mbox file
|
||||
*
|
||||
* @var null|resource
|
||||
*/
|
||||
protected $fh;
|
||||
|
||||
/**
|
||||
* filename of mbox file for __wakeup
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* modification date of mbox file for __wakeup
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $filemtime;
|
||||
|
||||
/**
|
||||
* start and end position of messages as array('start' => start, 'separator' => headersep, 'end' => end)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $positions;
|
||||
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message\File::class;
|
||||
protected $messageClass = File::class;
|
||||
|
||||
/**
|
||||
* end of Line for messages
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.ValidVariableName.NotCamelCapsProperty
|
||||
protected $messageEOL;
|
||||
|
||||
/**
|
||||
* Count messages all messages in current box
|
||||
*
|
||||
* @return int number of messages
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function countMessages()
|
||||
{
|
||||
@@ -95,21 +124,23 @@ class Mbox extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message\File
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return File
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
// TODO that's ugly, would be better to let the message class decide
|
||||
if (is_subclass_of($this->messageClass, Message\File::class)
|
||||
|| strtolower($this->messageClass) === strtolower(Message\File::class)) {
|
||||
if (
|
||||
is_subclass_of($this->messageClass, File::class)
|
||||
|| strtolower($this->messageClass) === strtolower(File::class)
|
||||
) {
|
||||
// TODO top/body lines
|
||||
$messagePos = $this->getPos($id);
|
||||
|
||||
$messageClassParams = [
|
||||
'file' => $this->fh,
|
||||
'file' => $this->fh,
|
||||
'startPos' => $messagePos['start'],
|
||||
'endPos' => $messagePos['end'],
|
||||
'endPos' => $messagePos['end'],
|
||||
];
|
||||
|
||||
if (isset($this->messageEOL)) {
|
||||
@@ -138,7 +169,7 @@ class Mbox extends AbstractStorage
|
||||
return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $message]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -146,7 +177,7 @@ class Mbox extends AbstractStorage
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawHeader($id, $part = null, $topLines = 0)
|
||||
{
|
||||
@@ -159,14 +190,14 @@ class Mbox extends AbstractStorage
|
||||
return stream_get_contents($this->fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message content
|
||||
* @return string raw content
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawContent($id, $part = null)
|
||||
{
|
||||
@@ -183,7 +214,7 @@ class Mbox extends AbstractStorage
|
||||
* Supported parameters are:
|
||||
* - filename filename of mbox file
|
||||
*
|
||||
* @param $params array|object|Config mail reader specific parameters
|
||||
* @param array|object|Config $params mail reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($params)
|
||||
@@ -228,7 +259,7 @@ class Mbox extends AbstractStorage
|
||||
$result = false;
|
||||
|
||||
$line = fgets($file) ?: '';
|
||||
if (strpos($line, 'From ') === 0) {
|
||||
if (str_starts_with($line, 'From ')) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
@@ -260,11 +291,11 @@ class Mbox extends AbstractStorage
|
||||
|
||||
ErrorHandler::start();
|
||||
$this->fh = fopen($filename, 'r');
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
if (! $this->fh) {
|
||||
throw new Exception\RuntimeException('cannot open mbox file', 0, $error);
|
||||
}
|
||||
$this->filename = $filename;
|
||||
$this->filename = $filename;
|
||||
$this->filemtime = filemtime($this->filename);
|
||||
|
||||
if (! $this->isMboxFile($this->fh, false)) {
|
||||
@@ -276,13 +307,13 @@ class Mbox extends AbstractStorage
|
||||
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
while (($line = fgets($this->fh)) !== false) {
|
||||
if (strpos($line, 'From ') === 0) {
|
||||
if (str_starts_with($line, 'From ')) {
|
||||
$messagePos['end'] = ftell($this->fh) - strlen($line) - 2; // + newline
|
||||
if (! $messagePos['separator']) {
|
||||
$messagePos['separator'] = $messagePos['end'];
|
||||
}
|
||||
$this->positions[] = $messagePos;
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
}
|
||||
if (! $messagePos['separator'] && ! trim($line)) {
|
||||
$messagePos['separator'] = ftell($this->fh);
|
||||
@@ -299,7 +330,6 @@ class Mbox extends AbstractStorage
|
||||
/**
|
||||
* Close resource for mail lib. If you need to control, when the resource
|
||||
* is closed. Otherwise the destructor would call this.
|
||||
*
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -322,7 +352,7 @@ class Mbox extends AbstractStorage
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id message number
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
@@ -339,7 +369,7 @@ class Mbox extends AbstractStorage
|
||||
*
|
||||
* @param int|null $id message number
|
||||
* @return array|string message number for given message or all messages as array
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getUniqueId($id = null)
|
||||
{
|
||||
@@ -361,7 +391,7 @@ class Mbox extends AbstractStorage
|
||||
*
|
||||
* @param string $id unique id
|
||||
* @return int message number
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getNumberByUniqueId($id)
|
||||
{
|
||||
|
||||
@@ -4,10 +4,17 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_combine;
|
||||
use function file_get_contents;
|
||||
use function is_resource;
|
||||
use function ltrim;
|
||||
use function stream_get_contents;
|
||||
|
||||
class Message extends Part implements Message\MessageInterface
|
||||
{
|
||||
/**
|
||||
* flags for this message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $flags = [];
|
||||
@@ -28,7 +35,7 @@ class Message extends Part implements Message\MessageInterface
|
||||
if (! is_resource($params['file'])) {
|
||||
ErrorHandler::start();
|
||||
$params['raw'] = file_get_contents($params['file']);
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
if ($params['raw'] === false) {
|
||||
throw new Exception\RuntimeException('could not open file', 0, $error);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
namespace Laminas\Mail\Storage\Message;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Part;
|
||||
|
||||
use function array_combine;
|
||||
|
||||
class File extends Part\File implements MessageInterface
|
||||
{
|
||||
/**
|
||||
* flags for this message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $flags = [];
|
||||
@@ -19,7 +23,7 @@ class File extends Part\File implements MessageInterface
|
||||
* - flags array with flags for message, keys are ignored, use constants defined in Laminas\Mail\Storage
|
||||
*
|
||||
* @param array $params
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct(array $params)
|
||||
{
|
||||
|
||||
@@ -5,16 +5,22 @@ namespace Laminas\Mail\Storage;
|
||||
use Traversable;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
use function get_object_vars;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function iterator_to_array;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ParamsNormalizer
|
||||
{
|
||||
/**
|
||||
* @param mixed $params
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function normalizeParams($params): array
|
||||
public static function normalizeParams(mixed $params): array
|
||||
{
|
||||
if ($params instanceof Traversable) {
|
||||
$params = iterator_to_array($params);
|
||||
|
||||
@@ -2,58 +2,81 @@
|
||||
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use ArrayIterator;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime;
|
||||
use Laminas\Mime\Exception\RuntimeException;
|
||||
use RecursiveIterator;
|
||||
use ReturnTypeWillChange;
|
||||
use Stringable;
|
||||
|
||||
class Part implements RecursiveIterator, Part\PartInterface
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function current;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function iterator_to_array;
|
||||
use function preg_replace;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
class Part implements RecursiveIterator, Part\PartInterface, Stringable
|
||||
{
|
||||
/**
|
||||
* Headers of the part
|
||||
*
|
||||
* @var Headers|null
|
||||
*/
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
* raw part body
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* toplines as fetched with headers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $topLines = '';
|
||||
|
||||
/**
|
||||
* parts of multipart message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parts = [];
|
||||
|
||||
/**
|
||||
* count of parts of a multipart message
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $countParts;
|
||||
|
||||
/**
|
||||
* current position of iterator
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $iterationPos = 1;
|
||||
|
||||
/**
|
||||
* mail handler, if late fetch is active
|
||||
*
|
||||
* @var null|AbstractStorage
|
||||
*/
|
||||
protected $mail;
|
||||
|
||||
/**
|
||||
* message number for mail handler
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $messageNum = 0;
|
||||
@@ -87,7 +110,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
$this->messageNum = $params['id'];
|
||||
}
|
||||
|
||||
$params['strict'] = $params['strict'] ?? false;
|
||||
$params['strict'] ??= false;
|
||||
|
||||
if (isset($params['raw'])) {
|
||||
Mime\Decode::splitMessage(
|
||||
@@ -124,7 +147,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
{
|
||||
try {
|
||||
return stripos($this->contentType, 'multipart/') === 0;
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -211,10 +234,10 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
throw new Exception\RuntimeException('part not found');
|
||||
}
|
||||
|
||||
if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// TODO: fetch part
|
||||
// return
|
||||
}
|
||||
// }
|
||||
|
||||
$this->cacheContent();
|
||||
|
||||
@@ -241,10 +264,10 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
return $this->countParts;
|
||||
}
|
||||
|
||||
if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// TODO: fetch part
|
||||
// return
|
||||
}
|
||||
// }
|
||||
|
||||
$this->cacheContent();
|
||||
|
||||
@@ -264,7 +287,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
{
|
||||
if (null === $this->headers) {
|
||||
if ($this->mail) {
|
||||
$part = $this->mail->getRawHeader($this->messageNum);
|
||||
$part = $this->mail->getRawHeader($this->messageNum);
|
||||
$this->headers = Headers::fromString($part);
|
||||
} else {
|
||||
$this->headers = new Headers();
|
||||
@@ -288,14 +311,14 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
|
||||
* @param string $format change type of return value to 'string' or 'array'
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return string|array|HeaderInterface|\ArrayIterator value of header in wanted or internal format
|
||||
* @return string|array|HeaderInterface|ArrayIterator value of header in wanted or internal format
|
||||
*/
|
||||
public function getHeader($name, $format = null)
|
||||
{
|
||||
$header = $this->getHeaders()->get($name);
|
||||
if ($header === false) {
|
||||
$lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
|
||||
$header = $this->getHeaders()->get($lowerName);
|
||||
$header = $this->getHeaders()->get($lowerName);
|
||||
if ($header === false) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
"Header with Name $name or $lowerName not found"
|
||||
@@ -310,9 +333,8 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
} else {
|
||||
$return = trim(implode(
|
||||
Mime\Mime::LINEEND,
|
||||
array_map(static function ($header): string {
|
||||
return $header->getFieldValue(HeaderInterface::FORMAT_RAW);
|
||||
}, iterator_to_array($header))
|
||||
array_map(static fn($header): string
|
||||
=> $header->getFieldValue(HeaderInterface::FORMAT_RAW), iterator_to_array($header))
|
||||
), Mime\Mime::LINEEND);
|
||||
}
|
||||
break;
|
||||
@@ -346,7 +368,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
|
||||
* @param string $firstName key name for the first part
|
||||
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
|
||||
* @throws \Laminas\Mime\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getHeaderField($name, $wantedPart = '0', $firstName = '0')
|
||||
{
|
||||
@@ -376,7 +398,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
*
|
||||
* @see Part::hasHeader
|
||||
*
|
||||
* @param string
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
@@ -389,7 +411,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
*
|
||||
* @return string content
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,26 @@ namespace Laminas\Mail\Storage\Part;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mail\Storage\Part;
|
||||
|
||||
use function count;
|
||||
use function feof;
|
||||
use function fgets;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fseek;
|
||||
use function ftell;
|
||||
use function is_resource;
|
||||
use function stream_copy_to_stream;
|
||||
use function trim;
|
||||
|
||||
use const SEEK_END;
|
||||
|
||||
class File extends Part
|
||||
{
|
||||
/** @var array */
|
||||
protected $contentPos = [];
|
||||
/** @var array */
|
||||
protected $partPos = [];
|
||||
/** @var resource */
|
||||
protected $fh;
|
||||
|
||||
/**
|
||||
@@ -31,13 +47,14 @@ class File extends Part
|
||||
}
|
||||
|
||||
if (! is_resource($params['file'])) {
|
||||
$this->fh = fopen($params['file'], 'r');
|
||||
$fh = fopen($params['file'], 'r');
|
||||
} else {
|
||||
$this->fh = $params['file'];
|
||||
$fh = $params['file'];
|
||||
}
|
||||
if (! $this->fh) {
|
||||
if (! $fh) {
|
||||
throw new Exception\RuntimeException('could not open file');
|
||||
}
|
||||
$this->fh = $fh;
|
||||
if (isset($params['startPos'])) {
|
||||
fseek($this->fh, $params['startPos']);
|
||||
}
|
||||
@@ -70,7 +87,7 @@ class File extends Part
|
||||
}
|
||||
|
||||
$part = [];
|
||||
$pos = $this->contentPos[0];
|
||||
$pos = $this->contentPos[0];
|
||||
fseek($this->fh, $pos);
|
||||
while (! feof($this->fh) && ($endPos === null || $pos < $endPos)) {
|
||||
$line = fgets($this->fh);
|
||||
@@ -82,18 +99,18 @@ class File extends Part
|
||||
}
|
||||
|
||||
$lastPos = $pos;
|
||||
$pos = ftell($this->fh);
|
||||
$line = trim($line);
|
||||
$pos = ftell($this->fh);
|
||||
$line = trim($line);
|
||||
|
||||
if ($line == '--' . $boundary) {
|
||||
if ($part) {
|
||||
// not first part
|
||||
$part[1] = $lastPos;
|
||||
$part[1] = $lastPos;
|
||||
$this->partPos[] = $part;
|
||||
}
|
||||
$part = [$pos];
|
||||
} elseif ($line == '--' . $boundary . '--') {
|
||||
$part[1] = $lastPos;
|
||||
$part[1] = $lastPos;
|
||||
$this->partPos[] = $part;
|
||||
break;
|
||||
}
|
||||
@@ -146,9 +163,9 @@ class File extends Part
|
||||
}
|
||||
|
||||
return new static([
|
||||
'file' => $this->fh,
|
||||
'file' => $this->fh,
|
||||
'startPos' => $this->partPos[$num][0],
|
||||
'endPos' => $this->partPos[$num][1],
|
||||
'endPos' => $this->partPos[$num][1],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ interface PartInterface extends RecursiveIterator
|
||||
* This getter is short for PartInterface::getHeader($name, 'string')
|
||||
*
|
||||
* @see PartInterface::getHeader()
|
||||
*
|
||||
* @param string $name header name
|
||||
* @return string value of header
|
||||
* @throws Exception\ExceptionInterface
|
||||
|
||||
@@ -4,12 +4,23 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail\Exception as MailException;
|
||||
use Laminas\Mail\Protocol;
|
||||
use Laminas\Mail\Protocol\Exception\RuntimeException;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Message;
|
||||
use Laminas\Mime;
|
||||
|
||||
use function array_combine;
|
||||
use function array_key_exists;
|
||||
use function is_string;
|
||||
use function range;
|
||||
use function strtolower;
|
||||
|
||||
class Pop3 extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* protocol handler
|
||||
*
|
||||
* @var null|\Laminas\Mail\Protocol\Pop3
|
||||
*/
|
||||
protected $protocol;
|
||||
@@ -18,7 +29,7 @@ class Pop3 extends AbstractStorage
|
||||
* Count messages all messages in current box
|
||||
*
|
||||
* @return int number of messages
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
*/
|
||||
public function countMessages()
|
||||
@@ -38,7 +49,7 @@ class Pop3 extends AbstractStorage
|
||||
*/
|
||||
public function getSize($id = 0)
|
||||
{
|
||||
$id = $id ? $id : null;
|
||||
$id = $id ?: null;
|
||||
return $this->protocol->getList($id);
|
||||
}
|
||||
|
||||
@@ -46,23 +57,23 @@ class Pop3 extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message
|
||||
* @return Message
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
$bodyLines = 0;
|
||||
$message = $this->protocol->top($id, $bodyLines, true);
|
||||
$message = $this->protocol->top($id, $bodyLines, true);
|
||||
|
||||
return new $this->messageClass([
|
||||
'handler' => $this,
|
||||
'id' => $id,
|
||||
'headers' => $message,
|
||||
'handler' => $this,
|
||||
'id' => $id,
|
||||
'headers' => $message,
|
||||
'noToplines' => $bodyLines < 1,
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -70,7 +81,7 @@ class Pop3 extends AbstractStorage
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawHeader($id, $part = null, $topLines = 0)
|
||||
{
|
||||
@@ -82,14 +93,14 @@ class Pop3 extends AbstractStorage
|
||||
return $this->protocol->top($id, 0, true);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message content
|
||||
* @return string raw content
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawContent($id, $part = null)
|
||||
{
|
||||
@@ -117,8 +128,8 @@ class Pop3 extends AbstractStorage
|
||||
*
|
||||
* @param array|object|Protocol\Pop3 $params mail reader specific
|
||||
* parameters or configured Pop3 protocol object
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
@@ -134,7 +145,7 @@ class Pop3 extends AbstractStorage
|
||||
$params = ParamsNormalizer::normalizeParams($params);
|
||||
|
||||
if (! isset($params['user'])) {
|
||||
throw new Exception\InvalidArgumentException('need at least user in params');
|
||||
throw new InvalidArgumentException('need at least user in params');
|
||||
}
|
||||
|
||||
$host = $params['host'] ?? 'localhost';
|
||||
@@ -172,7 +183,7 @@ class Pop3 extends AbstractStorage
|
||||
/**
|
||||
* Keep the server busy.
|
||||
*
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function noop()
|
||||
{
|
||||
@@ -185,7 +196,7 @@ class Pop3 extends AbstractStorage
|
||||
* identify the message.
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
{
|
||||
@@ -199,7 +210,7 @@ class Pop3 extends AbstractStorage
|
||||
*
|
||||
* @param int|null $id message number
|
||||
* @return array|string message number for given message or all messages as array
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getUniqueId($id = null)
|
||||
{
|
||||
@@ -225,7 +236,7 @@ class Pop3 extends AbstractStorage
|
||||
* as parameter and use this method to translate it to message number right before calling removeMessage()
|
||||
*
|
||||
* @param string $id unique id
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return int message number
|
||||
*/
|
||||
public function getNumberByUniqueId($id)
|
||||
@@ -241,7 +252,7 @@ class Pop3 extends AbstractStorage
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception\InvalidArgumentException('unique id not found');
|
||||
throw new InvalidArgumentException('unique id not found');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,8 +260,9 @@ class Pop3 extends AbstractStorage
|
||||
* retrieved if Top wasn't needed/tried yet.
|
||||
*
|
||||
* @see AbstractStorage::__get()
|
||||
*
|
||||
* @param string $var
|
||||
* @return string
|
||||
* @return null|string
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
@@ -264,7 +276,7 @@ class Pop3 extends AbstractStorage
|
||||
// need to make a real call, because not all server are honest in their capas
|
||||
try {
|
||||
$this->protocol->top(1, 0, false);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ignoring error
|
||||
}
|
||||
}
|
||||
@@ -276,7 +288,7 @@ class Pop3 extends AbstractStorage
|
||||
$id = null;
|
||||
try {
|
||||
$id = $this->protocol->uniqueid(1);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ignoring error
|
||||
}
|
||||
$this->has['uniqueid'] = (bool) $id;
|
||||
|
||||
@@ -5,10 +5,64 @@ namespace Laminas\Mail\Storage\Writable;
|
||||
use Laminas\Mail\Exception as MailException;
|
||||
use Laminas\Mail\Storage;
|
||||
use Laminas\Mail\Storage\Exception as StorageException;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Exception\RuntimeException;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
use function array_values;
|
||||
use function closedir;
|
||||
use function copy;
|
||||
use function dirname;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function filesize;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fwrite;
|
||||
use function get_resource_type;
|
||||
use function getmypid;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_numeric;
|
||||
use function is_resource;
|
||||
use function link;
|
||||
use function microtime;
|
||||
use function mkdir;
|
||||
use function opendir;
|
||||
use function php_uname;
|
||||
use function readdir;
|
||||
use function rename;
|
||||
use function rmdir;
|
||||
use function rtrim;
|
||||
use function sleep;
|
||||
use function str_contains;
|
||||
use function str_starts_with;
|
||||
use function stream_copy_to_stream;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
use function strtok;
|
||||
use function substr;
|
||||
use function time;
|
||||
use function trim;
|
||||
use function unlink;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
use const FILE_APPEND;
|
||||
|
||||
class Maildir extends Folder\Maildir implements WritableInterface
|
||||
{
|
||||
// TODO: init maildir (+ constructor option create if not found)
|
||||
@@ -26,8 +80,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* If the given dir is already a valid maildir this will not fail.
|
||||
*
|
||||
* @param string $dir directory for the new maildir (may already exist)
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function initMaildir($dir)
|
||||
{
|
||||
@@ -69,8 +123,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* Additional parameters are (see parent for more):
|
||||
* - create if true a new maildir is create if none exists
|
||||
*
|
||||
* @param $params array mail reader specific parameters
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @param array|object $params mail reader specific parameters
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
@@ -78,7 +132,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$params = (object) $params;
|
||||
}
|
||||
|
||||
if (! empty($params->create)
|
||||
if (
|
||||
! empty($params->create)
|
||||
&& isset($params->dirname)
|
||||
&& ! file_exists($params->dirname . DIRECTORY_SEPARATOR . 'cur')
|
||||
) {
|
||||
@@ -95,8 +150,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* may be used as parent or which chars may be used in the folder name
|
||||
*
|
||||
* @param string $name global name of folder, local name if $parentFolder is set
|
||||
* @param string|\Laminas\Mail\Storage\Folder $parentFolder parent of new folder, else root folder is parent
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $parentFolder parent of new folder, else root folder is parent
|
||||
* @throws RuntimeException
|
||||
* @return string only used internally (new created maildir)
|
||||
*/
|
||||
public function createFolder($name, $parentFolder = null)
|
||||
@@ -115,25 +170,26 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$exists = null;
|
||||
try {
|
||||
$exists = $this->getFolders($folder);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ok
|
||||
}
|
||||
if ($exists) {
|
||||
throw new StorageException\RuntimeException('folder already exists');
|
||||
}
|
||||
|
||||
if (strpos($folder, $this->delim . $this->delim) !== false) {
|
||||
if (str_contains($folder, $this->delim . $this->delim)) {
|
||||
throw new StorageException\RuntimeException('invalid name - folder parts may not be empty');
|
||||
}
|
||||
|
||||
if (strpos($folder, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($folder, 'INBOX' . $this->delim)) {
|
||||
$folder = substr($folder, 6);
|
||||
}
|
||||
|
||||
$fulldir = $this->rootdir . '.' . $folder;
|
||||
|
||||
// check if we got tricked and would create a dir outside of the rootdir or not as direct child
|
||||
if (strpos($folder, DIRECTORY_SEPARATOR) !== false || strpos($folder, '/') !== false
|
||||
if (
|
||||
str_contains($folder, DIRECTORY_SEPARATOR) || str_contains($folder, '/')
|
||||
|| dirname($fulldir) . DIRECTORY_SEPARATOR != $this->rootdir
|
||||
) {
|
||||
throw new StorageException\RuntimeException('invalid name - no directory separator allowed in folder name');
|
||||
@@ -146,7 +202,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$parent = substr($folder, 0, strrpos($folder, $this->delim));
|
||||
try {
|
||||
$this->getFolders($parent);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// does not - create parent folder
|
||||
$this->createFolder($parent);
|
||||
}
|
||||
@@ -176,7 +232,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* remove a folder
|
||||
*
|
||||
* @param string|Folder $name name or instance of folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeFolder($name)
|
||||
{
|
||||
@@ -191,7 +247,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$name = trim($name, $this->delim);
|
||||
if (strpos($name, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($name, 'INBOX' . $this->delim)) {
|
||||
$name = substr($name, 6);
|
||||
}
|
||||
|
||||
@@ -249,9 +305,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*
|
||||
* The new name has the same restrictions as in createFolder()
|
||||
*
|
||||
* @param string|\Laminas\Mail\Storage\Folder $oldName name or instance of folder
|
||||
* @param string|Folder $oldName name or instance of folder
|
||||
* @param string $newName new global name of folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameFolder($oldName, $newName)
|
||||
{
|
||||
@@ -262,16 +318,16 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$oldName = trim($oldName, $this->delim);
|
||||
if (strpos($oldName, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($oldName, 'INBOX' . $this->delim)) {
|
||||
$oldName = substr($oldName, 6);
|
||||
}
|
||||
|
||||
$newName = trim($newName, $this->delim);
|
||||
if (strpos($newName, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($newName, 'INBOX' . $this->delim)) {
|
||||
$newName = substr($newName, 6);
|
||||
}
|
||||
|
||||
if (strpos($newName, $oldName . $this->delim) === 0) {
|
||||
if (str_starts_with($newName, $oldName . $this->delim)) {
|
||||
throw new StorageException\RuntimeException('new folder cannot be a child of old folder');
|
||||
}
|
||||
|
||||
@@ -325,7 +381,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*/
|
||||
protected function createUniqueId()
|
||||
{
|
||||
$id = '';
|
||||
$id = '';
|
||||
$id .= microtime(true);
|
||||
$id .= '.' . getmypid();
|
||||
$id .= '.' . php_uname('n');
|
||||
@@ -340,7 +396,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* you should close the returned filehandle!
|
||||
*
|
||||
* @param string $folder name of current folder without leading .
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file
|
||||
* 'handle' => file opened for writing)
|
||||
*/
|
||||
@@ -385,10 +441,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'dirname' => $this->rootdir . '.' . $folder,
|
||||
'uniq' => $uniq,
|
||||
'dirname' => $this->rootdir . '.' . $folder,
|
||||
'uniq' => $uniq,
|
||||
'filename' => $tmpdir . $uniq,
|
||||
'handle' => $fh,
|
||||
'handle' => $fh,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -414,7 +470,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
if (! isset($wantedFlags[$flag])) {
|
||||
continue;
|
||||
}
|
||||
$info .= $char;
|
||||
$info .= $char;
|
||||
$flags[$char] = $flag;
|
||||
unset($wantedFlags[$flag]);
|
||||
}
|
||||
@@ -449,7 +505,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$folder = $this->currentFolder;
|
||||
}
|
||||
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
@@ -472,7 +528,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
if ($size !== false) {
|
||||
$info = ',S=' . $size . $info;
|
||||
}
|
||||
$newFilename = $tempFile['dirname'] . DIRECTORY_SEPARATOR;
|
||||
$newFilename = $tempFile['dirname'] . DIRECTORY_SEPARATOR;
|
||||
$newFilename .= $recent ? 'new' : 'cur';
|
||||
$newFilename .= DIRECTORY_SEPARATOR . $tempFile['uniq'] . $info;
|
||||
|
||||
@@ -492,8 +548,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$this->files[] = [
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'filename' => $newFilename,
|
||||
];
|
||||
if ($this->quota) {
|
||||
@@ -505,8 +561,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* copy an existing message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $folder name or instance of targer folder
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function copyMessage($id, $folder)
|
||||
{
|
||||
@@ -514,7 +570,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
throw new StorageException\RuntimeException('storage is over quota!');
|
||||
}
|
||||
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
@@ -558,12 +614,13 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($folder->getGlobalName() == $this->currentFolder
|
||||
if (
|
||||
$folder->getGlobalName() == $this->currentFolder
|
||||
|| ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
|
||||
) {
|
||||
$this->files[] = [
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'filename' => $newFile,
|
||||
];
|
||||
}
|
||||
@@ -577,16 +634,17 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* move an existing message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $folder name or instance of targer folder
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function moveMessage($id, $folder)
|
||||
{
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
if ($folder->getGlobalName() == $this->currentFolder
|
||||
if (
|
||||
$folder->getGlobalName() == $this->currentFolder
|
||||
|| ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
|
||||
) {
|
||||
throw new StorageException\RuntimeException('target is current folder');
|
||||
@@ -641,7 +699,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param array $flags new flags for message
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function setFlags($id, $flags)
|
||||
{
|
||||
@@ -672,8 +730,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param int $id
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
{
|
||||
@@ -716,8 +774,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* get currently set quota
|
||||
*
|
||||
* @see \Laminas\Mail\Storage\Writable\Maildir::setQuota()
|
||||
*
|
||||
* @param bool $fromStorage
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return bool|array
|
||||
*/
|
||||
public function getQuota($fromStorage = false)
|
||||
@@ -748,7 +807,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
|
||||
/**
|
||||
* @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize"
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @return array
|
||||
*/
|
||||
protected function calculateMaildirsize()
|
||||
@@ -842,7 +902,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'size' => $totalSize,
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
];
|
||||
@@ -850,6 +910,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
|
||||
/**
|
||||
* @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++"
|
||||
*
|
||||
* @param bool $forceRecalc
|
||||
* @return array
|
||||
*/
|
||||
@@ -859,7 +920,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$totalSize = 0;
|
||||
$messages = 0;
|
||||
$maildirsize = '';
|
||||
if (! $forceRecalc
|
||||
if (
|
||||
! $forceRecalc
|
||||
&& file_exists($this->rootdir . 'maildirsize')
|
||||
&& filesize($this->rootdir . 'maildirsize') < 5120
|
||||
) {
|
||||
@@ -874,10 +936,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
}
|
||||
if (! $fh) {
|
||||
$result = $this->calculateMaildirsize();
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
} else {
|
||||
$maildirsize = explode("\n", $maildirsize);
|
||||
if (is_array($this->quota)) {
|
||||
@@ -895,9 +957,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
unset($maildirsize[0]);
|
||||
foreach ($maildirsize as $line) {
|
||||
list($size, $count) = explode(' ', trim($line));
|
||||
$totalSize += $size;
|
||||
$messages += $count;
|
||||
[$size, $count] = explode(' ', trim($line));
|
||||
$totalSize += $size;
|
||||
$messages += $count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,10 +971,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
// Also we're using local time to calculate the 15 minute offset. Touching a file just for known the
|
||||
// local time of the file storage isn't worth the hassle.
|
||||
if ($overQuota && ($maildirsize || filemtime($this->rootdir . 'maildirsize') > time() - 900)) {
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$overQuota = false;
|
||||
$overQuota = $overQuota || (isset($quota['size']) && $totalSize > $quota['size']);
|
||||
$overQuota = $overQuota || (isset($quota['count']) && $messages > $quota['count']);
|
||||
@@ -924,20 +986,23 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
'over_quota' => $overQuota,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
* @param int $count
|
||||
* @return void
|
||||
*/
|
||||
protected function addQuotaEntry($size, $count = 1)
|
||||
{
|
||||
if (! file_exists($this->rootdir . 'maildirsize')) {
|
||||
// if (! file_exists($this->rootdir . 'maildirsize')) {
|
||||
// TODO: should get file handler from calculateQuota
|
||||
}
|
||||
$size = (int) $size;
|
||||
$count = (int) $count;
|
||||
// }
|
||||
file_put_contents($this->rootdir . 'maildirsize', "$size $count\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
@@ -945,6 +1010,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* check if storage is currently over quota
|
||||
*
|
||||
* @see calculateQuota()
|
||||
*
|
||||
* @param bool $detailedResponse return known data of quota and current size and message count
|
||||
* @param bool $forceRecalc
|
||||
* @return bool|array over quota state or detailed response
|
||||
|
||||
@@ -6,14 +6,10 @@ use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
class Envelope extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
protected $from;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
protected $to;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,18 +5,24 @@ namespace Laminas\Mail\Transport;
|
||||
use Laminas\Stdlib\ArrayUtils;
|
||||
use Traversable;
|
||||
|
||||
use function class_exists;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class Factory
|
||||
{
|
||||
/**
|
||||
* @var array Known transport types
|
||||
*/
|
||||
/** @var array Known transport types */
|
||||
protected static $classMap = [
|
||||
'file' => File::class,
|
||||
'inmemory' => InMemory::class,
|
||||
'memory' => InMemory::class,
|
||||
'null' => InMemory::class,
|
||||
'sendmail' => Sendmail::class,
|
||||
'smtp' => Smtp::class,
|
||||
'file' => File::class,
|
||||
'inmemory' => InMemory::class,
|
||||
'memory' => InMemory::class,
|
||||
'null' => InMemory::class,
|
||||
'sendmail' => Sendmail::class,
|
||||
'smtp' => Smtp::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -35,7 +41,7 @@ abstract class Factory
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects an array or Traversable argument; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($spec) ? get_class($spec) : gettype($spec))
|
||||
is_object($spec) ? $spec::class : gettype($spec)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Message;
|
||||
|
||||
use function file_put_contents;
|
||||
use function sprintf;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* File transport
|
||||
*
|
||||
@@ -11,9 +16,7 @@ use Laminas\Mail\Message;
|
||||
*/
|
||||
class File implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var FileOptions
|
||||
*/
|
||||
/** @var FileOptions */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
@@ -28,7 +31,7 @@ class File implements TransportInterface
|
||||
*
|
||||
* @param null|FileOptions $options OPTIONAL (Default: null)
|
||||
*/
|
||||
public function __construct(FileOptions $options = null)
|
||||
public function __construct(?FileOptions $options = null)
|
||||
{
|
||||
if (! $options instanceof FileOptions) {
|
||||
$options = new FileOptions();
|
||||
@@ -46,8 +49,6 @@ class File implements TransportInterface
|
||||
|
||||
/**
|
||||
* Sets options
|
||||
*
|
||||
* @param FileOptions $options
|
||||
*/
|
||||
public function setOptions(FileOptions $options)
|
||||
{
|
||||
@@ -57,9 +58,7 @@ class File implements TransportInterface
|
||||
/**
|
||||
* Saves e-mail message to a file
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException on not writable target directory or
|
||||
* on file_put_contents() failure
|
||||
* @throws Exception\RuntimeException On not writable target directory or on file_put_contents() failure.
|
||||
*/
|
||||
public function send(Message $message)
|
||||
{
|
||||
|
||||
@@ -3,25 +3,32 @@
|
||||
namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Exception;
|
||||
use Laminas\Mail\Exception\InvalidArgumentException;
|
||||
use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
use function gettype;
|
||||
use function is_callable;
|
||||
use function is_dir;
|
||||
use function is_object;
|
||||
use function is_writable;
|
||||
use function mt_rand;
|
||||
use function sprintf;
|
||||
use function sys_get_temp_dir;
|
||||
use function time;
|
||||
|
||||
class FileOptions extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string Path to stored mail files
|
||||
*/
|
||||
/** @var string Path to stored mail files */
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
/** @var callable */
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* Set path to stored mail files
|
||||
*
|
||||
* @param string $path
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return FileOptions
|
||||
*/
|
||||
public function setPath($path)
|
||||
@@ -56,7 +63,7 @@ class FileOptions extends AbstractOptions
|
||||
* Set callback used to generate a file name
|
||||
*
|
||||
* @param callable $callback
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return FileOptions
|
||||
*/
|
||||
public function setCallback($callback)
|
||||
@@ -65,7 +72,7 @@ class FileOptions extends AbstractOptions
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects a valid callback; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($callback) ? get_class($callback) : gettype($callback))
|
||||
is_object($callback) ? $callback::class : gettype($callback)
|
||||
));
|
||||
}
|
||||
$this->callback = $callback;
|
||||
@@ -80,9 +87,7 @@ class FileOptions extends AbstractOptions
|
||||
public function getCallback()
|
||||
{
|
||||
if (null === $this->callback) {
|
||||
$this->setCallback(function () {
|
||||
return 'LaminasMail_' . time() . '_' . mt_rand() . '.eml';
|
||||
});
|
||||
$this->setCallback(static fn() => 'LaminasMail_' . time() . '_' . mt_rand() . '.eml');
|
||||
}
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,11 @@ use Laminas\Mail\Message;
|
||||
*/
|
||||
class InMemory implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var null|Message
|
||||
*/
|
||||
/** @var null|Message */
|
||||
protected $lastMessage;
|
||||
|
||||
/**
|
||||
* Takes the last message and saves it for testing.
|
||||
*
|
||||
* @param Message $message
|
||||
*/
|
||||
public function send(Message $message)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,32 @@ namespace Laminas\Mail\Transport;
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Transport\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Transport\Exception\RuntimeException;
|
||||
use Traversable;
|
||||
|
||||
use function count;
|
||||
use function escapeshellarg;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function mail;
|
||||
use function preg_match;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const PHP_OS;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* Class for sending email via the PHP internal mail() function
|
||||
*/
|
||||
@@ -28,18 +52,15 @@ class Sendmail implements TransportInterface
|
||||
|
||||
/**
|
||||
* error information
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $errstr;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $operatingSystem;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param null|string|array|Traversable $parameters OPTIONAL (Default: null)
|
||||
*/
|
||||
public function __construct($parameters = null)
|
||||
@@ -56,7 +77,7 @@ class Sendmail implements TransportInterface
|
||||
* Used to populate the additional_parameters argument to mail()
|
||||
*
|
||||
* @param null|string|array|Traversable $parameters
|
||||
* @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return Sendmail
|
||||
*/
|
||||
public function setParameters($parameters)
|
||||
@@ -67,10 +88,10 @@ class Sendmail implements TransportInterface
|
||||
}
|
||||
|
||||
if (! is_array($parameters) && ! $parameters instanceof Traversable) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string, array, or Traversable object of parameters; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($parameters) ? get_class($parameters) : gettype($parameters))
|
||||
is_object($parameters) ? $parameters::class : gettype($parameters)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -89,16 +110,16 @@ class Sendmail implements TransportInterface
|
||||
* Primarily for testing purposes, but could be used to curry arguments.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return Sendmail
|
||||
*/
|
||||
public function setCallable($callable)
|
||||
{
|
||||
if (! is_callable($callable)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a callable argument; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($callable) ? get_class($callable) : gettype($callable))
|
||||
is_object($callable) ? $callable::class : gettype($callable)
|
||||
));
|
||||
}
|
||||
$this->callable = $callable;
|
||||
@@ -107,8 +128,6 @@ class Sendmail implements TransportInterface
|
||||
|
||||
/**
|
||||
* Send a message
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
*/
|
||||
public function send(Mail\Message $message)
|
||||
{
|
||||
@@ -133,8 +152,7 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare recipients list
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @throws \Laminas\Mail\Transport\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareRecipients(Mail\Message $message)
|
||||
@@ -143,7 +161,7 @@ class Sendmail implements TransportInterface
|
||||
|
||||
$hasTo = $headers->has('to');
|
||||
if (! $hasTo && ! $headers->has('cc') && ! $headers->has('bcc')) {
|
||||
throw new Exception\RuntimeException(
|
||||
throw new RuntimeException(
|
||||
'Invalid email; contains no at least one of "To", "Cc", and "Bcc" header'
|
||||
);
|
||||
}
|
||||
@@ -156,7 +174,7 @@ class Sendmail implements TransportInterface
|
||||
$to = $headers->get('to');
|
||||
$list = $to->getAddressList();
|
||||
if (0 == count($list)) {
|
||||
throw new Exception\RuntimeException('Invalid "To" header; contains no addresses');
|
||||
throw new RuntimeException('Invalid "To" header; contains no addresses');
|
||||
}
|
||||
|
||||
// If not on Windows, return normal string
|
||||
@@ -176,7 +194,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the subject line string
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareSubject(Mail\Message $message)
|
||||
@@ -192,7 +209,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the body string
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareBody(Mail\Message $message)
|
||||
@@ -211,7 +227,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the textual representation of headers
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareHeaders(Mail\Message $message)
|
||||
@@ -225,8 +240,8 @@ class Sendmail implements TransportInterface
|
||||
$from = $headers->get('From');
|
||||
if ($from) {
|
||||
foreach ($from->getAddressList() as $address) {
|
||||
if (strpos($address->getEmail(), '\\"') !== false) {
|
||||
throw new Exception\RuntimeException('Potential code injection in From header');
|
||||
if (str_contains($address->getEmail(), '\\"')) {
|
||||
throw new RuntimeException('Potential code injection in From header');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,7 +254,6 @@ class Sendmail implements TransportInterface
|
||||
* Basically, overrides the MAIL FROM envelope with either the Sender or
|
||||
* From address.
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareParameters(Mail\Message $message)
|
||||
@@ -255,16 +269,14 @@ class Sendmail implements TransportInterface
|
||||
|
||||
$sender = $message->getSender();
|
||||
if ($sender instanceof AddressInterface) {
|
||||
$parameters .= ' -f' . \escapeshellarg($sender->getEmail());
|
||||
return $parameters;
|
||||
return $parameters . ' -f' . escapeshellarg($sender->getEmail());
|
||||
}
|
||||
|
||||
$from = $message->getFrom();
|
||||
if (count($from)) {
|
||||
$from->rewind();
|
||||
$sender = $from->current();
|
||||
$parameters .= ' -f' . \escapeshellarg($sender->getEmail());
|
||||
return $parameters;
|
||||
$sender = $from->current();
|
||||
return $parameters . ' -f' . escapeshellarg($sender->getEmail());
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
@@ -277,8 +289,8 @@ class Sendmail implements TransportInterface
|
||||
* @param string $subject
|
||||
* @param string $message
|
||||
* @param string $headers
|
||||
* @param $parameters
|
||||
* @throws \Laminas\Mail\Transport\Exception\RuntimeException
|
||||
* @param null|string $parameters
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function mailHandler($to, $subject, $message, $headers, $parameters)
|
||||
{
|
||||
@@ -295,7 +307,7 @@ class Sendmail implements TransportInterface
|
||||
if (empty($errstr)) {
|
||||
$errstr = 'Unknown error';
|
||||
}
|
||||
throw new Exception\RuntimeException('Unable to send mail: ' . $errstr);
|
||||
throw new RuntimeException('Unable to send mail: ' . $errstr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +321,7 @@ class Sendmail implements TransportInterface
|
||||
* @param array $errcontext
|
||||
* @return bool always true
|
||||
*/
|
||||
public function handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
|
||||
public function handleMailErrors($errno, $errstr, $errfile = null, $errline = null, ?array $errcontext = null)
|
||||
{
|
||||
$this->errstr = $errstr;
|
||||
return true;
|
||||
@@ -325,6 +337,6 @@ class Sendmail implements TransportInterface
|
||||
if (! $this->operatingSystem) {
|
||||
$this->operatingSystem = strtoupper(substr(PHP_OS, 0, 3));
|
||||
}
|
||||
return ($this->operatingSystem == 'WIN');
|
||||
return $this->operatingSystem == 'WIN';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ use Laminas\Mail\Protocol;
|
||||
use Laminas\Mail\Protocol\Exception as ProtocolException;
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
|
||||
use function array_unique;
|
||||
use function count;
|
||||
use function sprintf;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* SMTP connection object
|
||||
*
|
||||
@@ -16,29 +21,19 @@ use Laminas\ServiceManager\ServiceManager;
|
||||
*/
|
||||
class Smtp implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var SmtpOptions
|
||||
*/
|
||||
/** @var SmtpOptions */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var Envelope|null
|
||||
*/
|
||||
/** @var Envelope|null */
|
||||
protected $envelope;
|
||||
|
||||
/**
|
||||
* @var Protocol\Smtp
|
||||
*/
|
||||
/** @var null|Protocol\Smtp */
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
/** @var bool */
|
||||
protected $autoDisconnect = true;
|
||||
|
||||
/**
|
||||
* @var Protocol\SmtpPluginManager
|
||||
*/
|
||||
/** @var Protocol\SmtpPluginManager */
|
||||
protected $plugins;
|
||||
|
||||
/**
|
||||
@@ -49,11 +44,9 @@ class Smtp implements TransportInterface
|
||||
protected $connectedTime;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param SmtpOptions $options Optional
|
||||
*/
|
||||
public function __construct(SmtpOptions $options = null)
|
||||
public function __construct(?SmtpOptions $options = null)
|
||||
{
|
||||
if (! $options instanceof SmtpOptions) {
|
||||
$options = new SmtpOptions();
|
||||
@@ -64,7 +57,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Set options
|
||||
*
|
||||
* @param SmtpOptions $options
|
||||
* @return Smtp
|
||||
*/
|
||||
public function setOptions(SmtpOptions $options)
|
||||
@@ -85,8 +77,6 @@ class Smtp implements TransportInterface
|
||||
|
||||
/**
|
||||
* Set options
|
||||
*
|
||||
* @param Envelope $envelope
|
||||
*/
|
||||
public function setEnvelope(Envelope $envelope)
|
||||
{
|
||||
@@ -106,7 +96,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Set plugin manager for obtaining SMTP protocol connection
|
||||
*
|
||||
* @param Protocol\SmtpPluginManager $plugins
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return Smtp
|
||||
*/
|
||||
@@ -155,10 +144,9 @@ class Smtp implements TransportInterface
|
||||
* Return an SMTP connection
|
||||
*
|
||||
* @param string $name
|
||||
* @param array|null $options
|
||||
* @return Protocol\Smtp
|
||||
*/
|
||||
public function plugin($name, array $options = null)
|
||||
public function plugin($name, ?array $options = null)
|
||||
{
|
||||
return $this->getPluginManager()->get($name, $options);
|
||||
}
|
||||
@@ -168,30 +156,30 @@ class Smtp implements TransportInterface
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (! $this->getConnection() instanceof Protocol\Smtp) {
|
||||
$connection = $this->getConnection();
|
||||
if (! $connection instanceof Protocol\Smtp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->getConnection()->quit();
|
||||
} catch (ProtocolException\ExceptionInterface $e) {
|
||||
$connection->quit();
|
||||
} catch (ProtocolException\ExceptionInterface) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if ($this->autoDisconnect) {
|
||||
$this->getConnection()->disconnect();
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection protocol instance
|
||||
*
|
||||
* @param Protocol\AbstractProtocol $connection
|
||||
*/
|
||||
public function setConnection(Protocol\AbstractProtocol $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
if (($connection instanceof Protocol\Smtp)
|
||||
if (
|
||||
$connection instanceof Protocol\Smtp
|
||||
&& ($this->getOptions()->getConnectionTimeLimit() !== null)
|
||||
) {
|
||||
$connection->setUseCompleteQuit(false);
|
||||
@@ -201,12 +189,13 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Gets the connection protocol instance
|
||||
*
|
||||
* @return Protocol\Smtp
|
||||
* @return null|Protocol\Smtp
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
$timeLimit = $this->getOptions()->getConnectionTimeLimit();
|
||||
if ($timeLimit !== null
|
||||
if (
|
||||
$timeLimit !== null
|
||||
&& $this->connectedTime !== null
|
||||
&& ((time() - $this->connectedTime) > $timeLimit)
|
||||
) {
|
||||
@@ -222,8 +211,9 @@ class Smtp implements TransportInterface
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
if ($this->getConnection() instanceof Protocol\Smtp) {
|
||||
$this->getConnection()->disconnect();
|
||||
$connection = $this->getConnection();
|
||||
if ($connection instanceof Protocol\Smtp) {
|
||||
$connection->disconnect();
|
||||
$this->connectedTime = null;
|
||||
}
|
||||
}
|
||||
@@ -234,7 +224,6 @@ class Smtp implements TransportInterface
|
||||
* The connection via the protocol adapter is made just-in-time to allow a
|
||||
* developer to add a custom adapter if required before mail is sent.
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function send(Message $message)
|
||||
@@ -242,7 +231,7 @@ class Smtp implements TransportInterface
|
||||
// If sending multiple messages per session use existing adapter
|
||||
$connection = $this->getConnection();
|
||||
|
||||
if (! ($connection instanceof Protocol\Smtp) || ! $connection->hasSession()) {
|
||||
if (! $connection instanceof Protocol\Smtp || ! $connection->hasSession()) {
|
||||
$connection = $this->connect();
|
||||
} else {
|
||||
// Reset connection to ensure reliable transaction
|
||||
@@ -260,7 +249,7 @@ class Smtp implements TransportInterface
|
||||
throw new Exception\RuntimeException(
|
||||
sprintf(
|
||||
'%s transport expects at least one recipient if the message has at least one header or body',
|
||||
__CLASS__
|
||||
self::class
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -280,7 +269,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Retrieve email address for envelope FROM
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
@@ -300,7 +288,7 @@ class Smtp implements TransportInterface
|
||||
// Per RFC 2822 3.6
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
'%s transport expects either a Sender or at least one From address in the Message; none provided',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
@@ -312,7 +300,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare array of email address recipients
|
||||
*
|
||||
* @param Message $message
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareRecipients(Message $message)
|
||||
@@ -339,7 +326,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare header string from message
|
||||
*
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareHeaders(Message $message)
|
||||
@@ -352,7 +338,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare body string from message
|
||||
*
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareBody(Message $message)
|
||||
@@ -368,10 +353,10 @@ class Smtp implements TransportInterface
|
||||
protected function lazyLoadConnection()
|
||||
{
|
||||
// Check if authentication is required and determine required class
|
||||
$options = $this->getOptions();
|
||||
$config = $options->getConnectionConfig();
|
||||
$config['host'] = $options->getHost();
|
||||
$config['port'] = $options->getPort();
|
||||
$options = $this->getOptions();
|
||||
$config = $options->getConnectionConfig();
|
||||
$config['host'] = $options->getHost();
|
||||
$config['port'] = $options->getPort();
|
||||
|
||||
$this->setConnection($this->plugin($options->getConnectionClass(), $config));
|
||||
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Exception;
|
||||
use Laminas\Mail\Exception\InvalidArgumentException;
|
||||
use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
class SmtpOptions extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string Local client hostname
|
||||
*/
|
||||
/** @var string Local client hostname */
|
||||
protected $name = 'localhost';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $connectionClass = 'smtp';
|
||||
|
||||
/**
|
||||
@@ -24,14 +26,10 @@ class SmtpOptions extends AbstractOptions
|
||||
*/
|
||||
protected $connectionConfig = [];
|
||||
|
||||
/**
|
||||
* @var string Remote SMTP hostname or IP
|
||||
*/
|
||||
/** @var string Remote SMTP hostname or IP */
|
||||
protected $host = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
protected $port = 25;
|
||||
|
||||
/**
|
||||
@@ -57,7 +55,7 @@ class SmtpOptions extends AbstractOptions
|
||||
*
|
||||
* @todo hostname/IP validation
|
||||
* @param string $name
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setName($name)
|
||||
@@ -65,7 +63,7 @@ class SmtpOptions extends AbstractOptions
|
||||
if (! is_string($name) && $name !== null) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Name must be a string or null; argument of type "%s" provided',
|
||||
(is_object($name) ? get_class($name) : gettype($name))
|
||||
is_object($name) ? $name::class : gettype($name)
|
||||
));
|
||||
}
|
||||
$this->name = $name;
|
||||
@@ -90,7 +88,7 @@ class SmtpOptions extends AbstractOptions
|
||||
* Set connection class
|
||||
*
|
||||
* @param string $connectionClass the value to be set
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setConnectionClass($connectionClass)
|
||||
@@ -98,7 +96,7 @@ class SmtpOptions extends AbstractOptions
|
||||
if (! is_string($connectionClass) && $connectionClass !== null) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Connection class must be a string or null; argument of type "%s" provided',
|
||||
(is_object($connectionClass) ? get_class($connectionClass) : gettype($connectionClass))
|
||||
is_object($connectionClass) ? $connectionClass::class : gettype($connectionClass)
|
||||
));
|
||||
}
|
||||
$this->connectionClass = $connectionClass;
|
||||
@@ -118,7 +116,6 @@ class SmtpOptions extends AbstractOptions
|
||||
/**
|
||||
* Set connection configuration array
|
||||
*
|
||||
* @param array $connectionConfig
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setConnectionConfig(array $connectionConfig)
|
||||
@@ -164,7 +161,7 @@ class SmtpOptions extends AbstractOptions
|
||||
* Set the port the SMTP server runs on
|
||||
*
|
||||
* @param int $port
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setPort($port)
|
||||
|
||||
@@ -12,8 +12,7 @@ interface TransportInterface
|
||||
/**
|
||||
* Send a mail message
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return
|
||||
* @return void
|
||||
*/
|
||||
public function send(Mail\Message $message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user