3 * @see https://github.com/zendframework/zend-mail for the canonical source repository
4 * @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (https://www.zend.com)
5 * @license https://github.com/zendframework/zend-mail/blob/master/LICENSE.md New BSD License
8 namespace Zend\Mail\Header
;
10 use TrueBV\Exception\OutOfBoundsException
;
12 use Zend\Mail\Address
;
13 use Zend\Mail\AddressList
;
14 use Zend\Mail\Headers
;
17 * Base class for headers composing address lists (to, from, cc, bcc, reply-to)
19 abstract class AbstractAddressList
implements HeaderInterface
24 protected $addressList;
27 * @var string Normalized field name
36 protected $encoding = 'ASCII';
39 * @var string lower case field name
41 protected static $type;
46 private static $punycode;
48 public static function fromString($headerLine)
50 list($fieldName, $fieldValue) = GenericHeader
::splitHeaderLine($headerLine);
51 if (strtolower($fieldName) !== static::$type) {
52 throw new Exception\
InvalidArgumentException(sprintf(
53 'Invalid header line for "%s" string',
59 $fieldValue = str_replace(Headers
::FOLDING
, ' ', $fieldValue);
60 $fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
61 $values = ListParser
::parse($fieldValue);
64 $addresses = array_map(
65 function ($value) use (&$wasEncoded) {
66 $decodedValue = HeaderWrap
::mimeDecodeValue($value);
67 $wasEncoded = $wasEncoded ||
($decodedValue !== $value);
69 $value = trim($decodedValue);
71 $comments = self
::getComments($value);
72 $value = self
::stripComments($value);
74 $value = preg_replace(
76 '#(?<!\\\)"(.*)(?<!\\\)"#', // quoted-text
77 '#\\\([\x01-\x09\x0b\x0c\x0e-\x7f])#', // quoted-pair
86 return empty($value) ?
null : Address
::fromString($value, $comments);
90 $addresses = array_filter($addresses);
92 $header = new static();
94 $header->setEncoding('UTF-8');
97 /** @var AddressList $addressList */
98 $addressList = $header->getAddressList();
99 foreach ($addresses as $address) {
100 $addressList->add($address);
106 public function getFieldName()
108 return $this->fieldName
;
112 * Safely convert UTF-8 encoded domain name to ASCII
113 * @param string $domainName the UTF-8 encoded email
116 protected function idnToAscii($domainName)
118 if (null === self
::$punycode) {
119 self
::$punycode = new Punycode();
122 return self
::$punycode->encode($domainName);
123 } catch (OutOfBoundsException
$e) {
128 public function getFieldValue($format = HeaderInterface
::FORMAT_RAW
)
131 $encoding = $this->getEncoding();
133 foreach ($this->getAddressList() as $address) {
134 $email = $address->getEmail();
135 $name = $address->getName();
137 if (! empty($name) && false !== strstr($name, ',')) {
138 $name = sprintf('"%s"', $name);
141 if ($format === HeaderInterface
::FORMAT_ENCODED
142 && 'ASCII' !== $encoding
144 if (! empty($name)) {
145 $name = HeaderWrap
::mimeEncodeValue($name, $encoding);
148 if (preg_match('/^(.+)@([^@]+)$/', $email, $matches)) {
149 $localPart = $matches[1];
150 $hostname = $this->idnToAscii($matches[2]);
151 $email = sprintf('%s@%s', $localPart, $hostname);
158 $emails[] = sprintf('%s <%s>', $name, $email);
162 // Ensure the values are valid before sending them.
163 if ($format !== HeaderInterface
::FORMAT_RAW
) {
164 foreach ($emails as $email) {
165 HeaderValue
::assertValid($email);
169 return implode(',' . Headers
::FOLDING
, $emails);
172 public function setEncoding($encoding)
174 $this->encoding
= $encoding;
178 public function getEncoding()
180 return $this->encoding
;
184 * Set address list for this header
186 * @param AddressList $addressList
188 public function setAddressList(AddressList
$addressList)
190 $this->addressList
= $addressList;
194 * Get address list managed by this header
196 * @return AddressList
198 public function getAddressList()
200 if (null === $this->addressList
) {
201 $this->setAddressList(new AddressList());
203 return $this->addressList
;
206 public function toString()
208 $name = $this->getFieldName();
209 $value = $this->getFieldValue(HeaderInterface
::FORMAT_ENCODED
);
210 return (empty($value)) ?
'' : sprintf('%s: %s', $name, $value);
214 * Retrieve comments from value, if any.
216 * Supposed to be private, protected as a workaround for PHP bug 68194
218 * @param string $value
221 protected static function getComments($value)
234 return isset($matches['comment']) ?
implode(', ', $matches['comment']) : '';
238 * Strip all comments from value, if any.
240 * Supposed to be private, protected as a workaround for PHP bug 68194
242 * @param string $value
245 protected static function stripComments($value)