Passed
Push — master ( 181d77...7fe46a )
by Zaahid
06:13 queued 12s
created

ReceivedHeader   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Test Coverage

Coverage 94.12%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
eloc 26
c 1
b 0
f 0
dl 0
loc 172
ccs 32
cts 34
cp 0.9412
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getValue() 0 3 1
A getFromName() 0 4 2
A getFromHostname() 0 4 2
A getDateTime() 0 3 1
A getByAddress() 0 4 2
A getByName() 0 4 2
A getFromAddress() 0 4 2
A getComments() 0 3 1
A getByHostname() 0 4 2
A getConsumer() 0 3 1
A setParseHeaderValue() 0 11 4
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
8
namespace ZBateson\MailMimeParser\Header;
9
10
use DateTime;
11
use ZBateson\MailMimeParser\Header\Consumer\AbstractConsumer;
12
use ZBateson\MailMimeParser\Header\Consumer\ConsumerService;
13
use ZBateson\MailMimeParser\Header\Part\CommentPart;
14
use ZBateson\MailMimeParser\Header\Part\DatePart;
15
16
/**
17
 * Represents a Received header.
18
 *
19
 * The returned header value (as returned by a call to {@see
20
 * ReceivedHeader::getValue()}) for a
21
 * ReceivedHeader is the same as the raw value (as returned by a call to
22
 * {@see ReceivedHeader::getRawValue()}) since the header doesn't have a single
23
 * 'value' to consider 'the value'.
24
 *
25
 * The parsed parts of a Received header can be accessed as parameters.  To
26
 * check if a part exists, call {@see ReceivedHeader::hasParameter()} with the
27
 * name of the part, for example: ```php $header->hasParameter('from') ``` or
28
 * ```php $header->hasParameter('id') ```.  The value of the part can be obtained
29
 * by calling {@see ReceivedHeader::getValueFor()}, for example
30
 * ```php $header->getValueFor('with'); ```.
31
 *
32
 * Additional parsing is performed on the "FROM" and "BY" parts of a received
33
 * header in an attempt to extract the self-identified name of the server, its
34
 * hostname, and its address (depending on what's included).  These can be
35
 * accessed directly from the ReceivedHeader object by calling one of the
36
 * following methods:
37
 *
38
 * o {@see ReceivedHeader::getFromName()} -- the name portion of the FROM part
39
 * o {@see ReceivedHeader::getFromHostname()} -- the hostname of the FROM part
40
 * o {@see ReceivedHeader::getFromAddress()} -- the adddress portion of the FROM
41
 *   part
42
 * o {@see ReceivedHeader::getByName()} -- same as getFromName, but for the BY
43
 *   part, and etc... below
44
 * o {@see ReceivedHeader::getByHostname()}
45
 * o {@see ReceivedHeader::getByAddress()}
46
 *
47
 * The parsed parts of the FROM and BY parts are determined as follows:
48
 *
49
 * o Anything outside and before a parenthesized expression is considered "the
50
 *   name", for example "FROM AlainDeBotton", "AlainDeBotton" would be the name,
51
 *   but also if the name is an address, but exists outside the parenthesized
52
 *   expression, it's still considered "the name".  For example:
53
 *   "From [1.2.3.4]", getFromName would return "[1.2.3.4]".
54
 * o A parenthesized expression MUST match what looks like either a domain name
55
 *   on its own, or a domain name and an address.  Otherwise the parenthesized
56
 *   expression is considered a comment, and not parsed into hostname and
57
 *   address.  The rules are defined loosely because many implementations differ
58
 *   in how strictly they follow the standard.  For a domain, it's enough that
59
 *   the expression starts with any alphanumeric character and contains at least
60
 *   one '.', followed by any number of '.', '-' and alphanumeric characters.
61
 *   The address portion must be surrounded in square brackets, and contain any
62
 *   sequence of '.', ':', numbers, and characters 'a' through 'f'.  In addition
63
 *   the string 'ipv6' may start the expression (for instance, '[ipv6:::1]'
64
 *   would be valid).  A port number may also be considered valid as part of the
65
 *   address, for example: [1.2.3.4:3231].  No additional validation on the
66
 *   address is done, and so an invalid address such as '....' could be
67
 *   returned, so users using the 'address' header are encouraged to validate it
68
 *   before using it.  The square brackets are parsed out of the returned
69
 *   address, so the value returned by getFromAddress() would be "2.2.2.2", not
70
 *   "[2.2.2.2]".
71
 *
72
 * The date/time stamp can be accessed as a DateTime object by calling
73
 * {@see ReceivedHeader::getDateTime()}.
74
 *
75
 * Parsed comments can be accessed by calling {@see
76
 * ReceivedHeader::getComments()}.  Some implementations may include connection
77
 * encryption information or other details in non-standardized comments.
78
 *
79
 * @author Zaahid Bateson
80
 */
81
class ReceivedHeader extends ParameterHeader
82
{
83
    /**
84
     * @var string[] an array of comments in the header.
85
     */
86
    protected $comments = [];
87
88
    /**
89
     * @var DateTime the date/time stamp in the header.
90
     */
91
    protected $date = null;
92
93
    /**
94
     * Returns a ReceivedConsumer.
95
     *
96
     * @return Consumer\AbstractConsumer
97
     */
98 6
    protected function getConsumer(ConsumerService $consumerService)
99
    {
100 6
        return $consumerService->getReceivedConsumer();
101
    }
102
103
    /**
104
     * Overridden to assign comments to $this->comments, and the DateTime to
105
     * $this->date.
106
     *
107
     * @return static
108
     */
109 6
    protected function setParseHeaderValue(AbstractConsumer $consumer)
110
    {
111 6
        parent::setParseHeaderValue($consumer);
112 6
        foreach ($this->parts as $part) {
113 6
            if ($part instanceof CommentPart) {
114 3
                $this->comments[] = $part->getComment();
115 6
            } elseif ($part instanceof DatePart) {
116 3
                $this->date = $part->getDateTime();
117
            }
118
        }
119 6
        return $this;
120
    }
121
122
    /**
123
     * Returns the raw, unparsed header value, same as {@see
124
     * ReceivedHeader::getRawValue()}.
125
     */
126
    public function getValue() : ?string
127
    {
128
        return $this->rawValue;
129
    }
130
131
    /**
132
     * Returns the name identified in the FROM part of the header or null if not
133
     * defined or the format wasn't parsed.
134
     *
135
     * The returned value may either be a name or an address in the form
136
     * "[1.2.3.4]".  Validation is not performed on this value, and so whatever
137
     * exists in this position is returned -- be it contains spaces, or invalid
138
     * characters, etc...
139
     *
140
     * @return string|null The 'FROM' name.
141
     */
142 5
    public function getFromName()
143
    {
144 5
        return (isset($this->parameters['from'])) ?
145 5
            $this->parameters['from']->getEhloName() : null;
0 ignored issues
show
Bug introduced by
The method getEhloName() does not exist on ZBateson\MailMimeParser\Header\Part\ParameterPart. Did you maybe mean getName()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

145
            $this->parameters['from']->/** @scrutinizer ignore-call */ 
146
                                       getEhloName() : null;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
146
    }
147
148
    /**
149
     * Returns the hostname part of a parenthesized FROM part or null if not
150
     * defined or the format wasn't parsed.
151
     *
152
     * For example, "FROM name (host.name)" would return the string "host.name".
153
     * Validation of the hostname is not performed, and the returned value may
154
     * not be valid.  More details on how the value is parsed and extracted can
155
     * be found in the class description for {@see ReceivedHeader}.
156
     *
157
     * @return string|null The 'FROM' hostname.
158
     */
159 4
    public function getFromHostname()
160
    {
161 4
        return (isset($this->parameters['from'])) ?
162 4
            $this->parameters['from']->getHostname() : null;
0 ignored issues
show
Bug introduced by
The method getHostname() does not exist on ZBateson\MailMimeParser\Header\Part\ParameterPart. It seems like you code against a sub-type of ZBateson\MailMimeParser\Header\Part\ParameterPart such as ZBateson\MailMimeParser\...Part\ReceivedDomainPart. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

162
            $this->parameters['from']->/** @scrutinizer ignore-call */ 
163
                                       getHostname() : null;
Loading history...
163
    }
164
165
    /**
166
     * Returns the address part of a parenthesized FROM part or null if not
167
     * defined or the format wasn't parsed.
168
     *
169
     * For example, "FROM name ([1.2.3.4])" would return the string "1.2.3.4".
170
     * Validation of the address is not performed, and the returned value may
171
     * not be valid.  More details on how the value is parsed and extracted can
172
     * be found in the class description for {@see ReceivedHeader}.
173
     *
174
     * @return string|null The 'FROM' address.
175
     */
176 5
    public function getFromAddress()
177
    {
178 5
        return (isset($this->parameters['from'])) ?
179 5
            $this->parameters['from']->getAddress() : null;
0 ignored issues
show
Bug introduced by
The method getAddress() does not exist on ZBateson\MailMimeParser\Header\Part\ParameterPart. It seems like you code against a sub-type of ZBateson\MailMimeParser\Header\Part\ParameterPart such as ZBateson\MailMimeParser\...Part\ReceivedDomainPart. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

179
            $this->parameters['from']->/** @scrutinizer ignore-call */ 
180
                                       getAddress() : null;
Loading history...
180
    }
181
182
    /**
183
     * Returns the name identified in the BY part of the header or null if not
184
     * defined or the format wasn't parsed.
185
     *
186
     * The returned value may either be a name or an address in the form
187
     * "[1.2.3.4]".  Validation is not performed on this value, and so whatever
188
     * exists in this position is returned -- be it contains spaces, or invalid
189
     * characters, etc...
190
     *
191
     * @return string|null The 'BY' name.
192
     */
193 3
    public function getByName()
194
    {
195 3
        return (isset($this->parameters['by'])) ?
196 3
            $this->parameters['by']->getEhloName() : null;
197
    }
198
199
    /**
200
     * Returns the hostname part of a parenthesized BY part or null if not
201
     * defined or the format wasn't parsed.
202
     *
203
     * For example, "BY name (host.name)" would return the string "host.name".
204
     * Validation of the hostname is not performed, and the returned value may
205
     * not be valid.  More details on how the value is parsed and extracted can
206
     * be found in the class description for {@see ReceivedHeader}.
207
     *
208
     * @return string|null The 'BY' hostname.
209
     */
210 3
    public function getByHostname()
211
    {
212 3
        return (isset($this->parameters['by'])) ?
213 3
            $this->parameters['by']->getHostname() : null;
214
    }
215
216
    /**
217
     * Returns the address part of a parenthesized BY part or null if not
218
     * defined or the format wasn't parsed.
219
     *
220
     * For example, "BY name ([1.2.3.4])" would return the string "1.2.3.4".
221
     * Validation of the address is not performed, and the returned value may
222
     * not be valid.  More details on how the value is parsed and extracted can
223
     * be found in the class description for {@see ReceivedHeader}.
224
     *
225
     * @return string|null The 'BY' address.
226
     */
227 3
    public function getByAddress()
228
    {
229 3
        return (isset($this->parameters['by'])) ?
230 3
            $this->parameters['by']->getAddress() : null;
231
    }
232
233
    /**
234
     * Returns an array of comments parsed from the header.  If there are no
235
     * comments in the header, an empty array is returned.
236
     *
237
     * @return string[]
238
     */
239 1
    public function getComments()
240
    {
241 1
        return $this->comments;
242
    }
243
244
    /**
245
     * Returns the date/time stamp for the received header if set, or null
246
     * otherwise.
247
     *
248
     * @return \DateTime|null
249
     */
250 4
    public function getDateTime()
251
    {
252 4
        return $this->date;
253
    }
254
}
255