1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of the ZBateson\MailMimeParser project. |
4
|
|
|
* |
5
|
|
|
* @license http://opensource.org/licenses/bsd-license.php BSD |
6
|
|
|
*/ |
7
|
|
|
namespace ZBateson\MailMimeParser\Header\Consumer; |
8
|
|
|
|
9
|
|
|
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart; |
10
|
|
|
use ZBateson\MailMimeParser\Header\Part\AddressPart; |
11
|
|
|
use ZBateson\MailMimeParser\Header\Part\CommentPart; |
12
|
|
|
use ZBateson\MailMimeParser\Header\Part\LiteralPart; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Parses a single part of an address header. |
16
|
|
|
* |
17
|
|
|
* Represents a single part of a list of addresses. A part could be one email |
18
|
|
|
* address, or one 'group' containing multiple addresses. The consumer ends on |
19
|
|
|
* finding either a comma token, representing a separation between addresses, or |
20
|
|
|
* a semi-colon token representing the end of a group. |
21
|
|
|
* |
22
|
|
|
* A single email address may consist of just an email, or a name and an email |
23
|
|
|
* address. Both of these are valid examples of a From header: |
24
|
|
|
* - From: [email protected] |
25
|
|
|
* - From: Jon Snow <[email protected]> |
26
|
|
|
* |
27
|
|
|
* Groups must be named, for example: |
28
|
|
|
* - To: Winterfell: [email protected], Arya Stark <[email protected]>; |
29
|
|
|
* |
30
|
|
|
* Addresses may contain quoted parts and comments, and names may be mime-header |
31
|
|
|
* encoded. |
32
|
|
|
* |
33
|
|
|
* @author Zaahid Bateson |
34
|
|
|
*/ |
35
|
|
|
class AddressConsumer extends AbstractConsumer |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* Returns the following as sub-consumers: |
39
|
|
|
* - {@see AddressGroupConsumer} |
40
|
|
|
* - {@see CommentConsumer} |
41
|
|
|
* - {@see QuotedStringConsumer} |
42
|
|
|
* |
43
|
|
|
* @return AbstractConsumer[] the sub-consumers |
44
|
|
|
*/ |
45
|
103 |
|
protected function getSubConsumers() |
46
|
|
|
{ |
47
|
103 |
|
return [ |
48
|
103 |
|
$this->consumerService->getAddressGroupConsumer(), |
49
|
103 |
|
$this->consumerService->getAddressEmailConsumer(), |
50
|
103 |
|
$this->consumerService->getCommentConsumer(), |
51
|
103 |
|
$this->consumerService->getQuotedStringConsumer(), |
52
|
103 |
|
]; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Overridden to return patterns matching end tokens ("," and ";"), and |
57
|
|
|
* whitespace. |
58
|
|
|
* |
59
|
|
|
* @return string[] the patterns |
60
|
|
|
*/ |
61
|
103 |
|
public function getTokenSeparators() |
62
|
|
|
{ |
63
|
103 |
|
return [ ',', ';', '\s+' ]; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Returns true for commas and semi-colons. |
68
|
|
|
* |
69
|
|
|
* Although the semi-colon is not strictly the end token of an |
70
|
|
|
* AddressConsumer, it could end a parent AddressGroupConsumer. |
71
|
|
|
* |
72
|
|
|
* @param string $token |
73
|
|
|
* @return boolean false |
74
|
|
|
*/ |
75
|
103 |
|
protected function isEndToken($token) |
76
|
|
|
{ |
77
|
103 |
|
return ($token === ',' || $token === ';'); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* AddressConsumer is "greedy", so this always returns true. |
82
|
|
|
* |
83
|
|
|
* @param string $token |
84
|
|
|
* @return boolean false |
85
|
|
|
*/ |
86
|
95 |
|
protected function isStartToken($token) |
87
|
|
|
{ |
88
|
95 |
|
return true; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Performs final processing on parsed parts. |
93
|
|
|
* |
94
|
|
|
* AddressConsumer's implementation looks for tokens representing the |
95
|
|
|
* beginning of an address part, to create a Part\AddressPart out of a |
96
|
|
|
* name/address pair, or assign the name part to a parsed |
97
|
|
|
* Part\AddressGroupPart returned from its AddressGroupConsumer |
98
|
|
|
* sub-consumer. |
99
|
|
|
* |
100
|
|
|
* The returned array consists of a single element - either a |
101
|
|
|
* Part\AddressPart or a Part\AddressGroupPart. |
102
|
|
|
* |
103
|
|
|
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts |
104
|
|
|
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]|array |
105
|
|
|
*/ |
106
|
103 |
|
protected function processParts(array $parts) |
107
|
|
|
{ |
108
|
103 |
|
$strName = ''; |
109
|
103 |
|
$strEmail = ''; |
110
|
103 |
|
foreach ($parts as $part) { |
111
|
103 |
|
if ($part instanceof AddressGroupPart) { |
112
|
1 |
|
return [ |
113
|
1 |
|
$this->partFactory->newAddressGroupPart( |
114
|
1 |
|
$part->getAddresses(), |
115
|
1 |
|
$strName |
116
|
1 |
|
) |
117
|
1 |
|
]; |
118
|
103 |
|
} elseif ($part instanceof AddressPart) { |
119
|
96 |
|
return [ $this->partFactory->newAddressPart($strName, $part->getEmail()) ]; |
120
|
103 |
|
} elseif ((($part instanceof LiteralPart) && !($part instanceof CommentPart)) && $part->getValue() !== '') { |
121
|
55 |
|
$strEmail .= '"' . preg_replace('/(["\\\])/', "\\\\$1", $part->getValue()) . '"'; |
|
|
|
|
122
|
|
|
} else { |
123
|
103 |
|
$strEmail .= preg_replace('/\s+/', '', $part->getValue()); |
124
|
|
|
} |
125
|
103 |
|
$strName .= $part->getValue(); |
126
|
|
|
} |
127
|
8 |
|
return [ $this->partFactory->newAddressPart('', $strEmail) ]; |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
PHP provides two ways to mark string literals. Either with single quotes
'literal'
or with double quotes"literal"
. The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (
\'
) and the backslash (\\
). Every other character is displayed as is.Double quoted string literals may contain other variables or more complex escape sequences.
will print an indented:
Single is Value
If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.
For more information on PHP string literals and available escape sequences see the PHP core documentation.