Passed
Push — master ( 16bd50...cbcb00 )
by Zaahid
03:19
created

MimePart::getHeaderAs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1
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\Message;
9
10
use ZBateson\MailMimeParser\Header\HeaderConsts;
11
use ZBateson\MailMimeParser\Header\IHeader;
12
use ZBateson\MailMimeParser\Header\ParameterHeader;
13
use ZBateson\MailMimeParser\IMessage;
14
use ZBateson\MailMimeParser\MailMimeParser;
15
16
/**
17
 * A mime email message part.
18
 *
19
 * A MIME part may contain any combination of headers, content and children.
20
 *
21
 * @author Zaahid Bateson
22
 */
23
class MimePart extends MultiPart implements IMimePart
24
{
25
    /**
26
     * @var PartHeaderContainer Container for this part's headers.
27
     */
28
    protected $headerContainer;
29
30 140
    public function __construct(
31
        ?IMimePart $parent = null,
32
        ?PartStreamContainer $streamContainer = null,
33
        ?PartHeaderContainer $headerContainer = null,
34
        ?PartChildrenContainer $partChildrenContainer = null
35
    ) {
36 140
        $setStream = false;
37 140
        $di = MailMimeParser::getDependencyContainer();
38 140
        if ($streamContainer === null || $headerContainer === null || $partChildrenContainer === null) {
39
            $headerContainer = $di[\ZBateson\MailMimeParser\Message\PartHeaderContainer::class];
40
            $streamContainer = $di[\ZBateson\MailMimeParser\Message\PartStreamContainer::class];
41
            $partChildrenContainer = $di[\ZBateson\MailMimeParser\Message\PartChildrenContainer::class];
42
            $setStream = true;
43
        }
44 140
        parent::__construct(
45 140
            $parent,
46 140
            $streamContainer,
47 140
            $partChildrenContainer
48 140
        );
49 140
        if ($setStream) {
50
            $streamFactory = $di[\ZBateson\MailMimeParser\Stream\StreamFactory::class];
51
            $streamContainer->setStream($streamFactory->newMessagePartStream($this));
52
        }
53 140
        $this->headerContainer = $headerContainer;
54
    }
55
56
    /**
57
     * Returns a filename for the part if one is defined, or null otherwise.
58
     *
59
     * Uses the 'filename' parameter of the Content-Disposition header if it
60
     * exists, or the 'name' parameter of the 'Content-Type' header if it
61
     * doesn't.
62
     *
63
     * @return string|null the file name of the part or null.
64
     */
65 56
    public function getFilename() : ?string
66
    {
67 56
        return $this->getHeaderParameter(
68 56
            HeaderConsts::CONTENT_DISPOSITION,
69 56
            'filename',
70 56
            $this->getHeaderParameter(
71 56
                HeaderConsts::CONTENT_TYPE,
72 56
                'name'
73 56
            )
74 56
        );
75
    }
76
77
    /**
78
     * Returns true.
79
     *
80
     */
81 2
    public function isMime() : bool
82
    {
83 2
        return true;
84
    }
85
86 57
    public function isMultiPart()
87
    {
88
        // casting to bool, preg_match returns 1 for true
89 57
        return (bool) (\preg_match(
90 57
            '~multipart/.*~i',
91 57
            $this->getContentType()
92 57
        ));
93
    }
94
95
    /**
96
     * Returns true if this part has a defined 'charset' on its Content-Type
97
     * header.
98
     *
99
     * This may result in some false positives if charset is set on a part that
100
     * is not plain text which has been seen.  If a part is known to be binary,
101
     * it's better to use {@see IMessagePart::getBinaryContentStream()} to
102
     * avoid issues, or to call {@see IMessagePart::saveContent()} directly if
103
     * saving a part's content.
104
     *
105
     */
106 48
    public function isTextPart() : bool
107
    {
108 48
        return ($this->getCharset() !== null);
109
    }
110
111
    /**
112
     * Returns the mime type of the content, or $default if one is not set.
113
     *
114
     * Looks at the part's Content-Type header and returns its value if set, or
115
     * defaults to 'text/plain'.
116
     *
117
     * Note that the returned value is converted to lower case, and may not be
118
     * identical to calling {@see MimePart::getHeaderValue('Content-Type')} in
119
     * some cases.
120
     *
121
     * @param string $default Optional default value to specify a default other
122
     *        than text/plain if needed.
123
     * @return string the mime type
124
     */
125 109
    public function getContentType(string $default = 'text/plain') : ?string
126
    {
127 109
        return \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TYPE, $default));
128
    }
129
130
    /**
131
     * Returns the charset of the content, or null if not applicable/defined.
132
     *
133
     * Looks for a 'charset' parameter under the 'Content-Type' header of this
134
     * part and returns it if set, defaulting to 'ISO-8859-1' if the
135
     * Content-Type header exists and is of type text/plain or text/html.
136
     *
137
     * Note that the returned value is also converted to upper case.
138
     *
139
     * @return string|null the charset
140
     */
141 105
    public function getCharset() : ?string
142
    {
143 105
        $charset = $this->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'charset');
144 105
        if ($charset === null || \strcasecmp($charset, 'binary') === 0) {
145 77
            $contentType = $this->getContentType();
146 77
            if ($contentType === 'text/plain' || $contentType === 'text/html') {
147 11
                return 'ISO-8859-1';
148
            }
149 69
            return null;
150
        }
151 84
        return \strtoupper($charset);
152
    }
153
154
    /**
155
     * Returns the content's disposition, or returns the value of $default if
156
     * not defined.
157
     *
158
     * Looks at the 'Content-Disposition' header, which should only contain
159
     * either 'inline' or 'attachment'.  If the header is not one of those
160
     * values, $default is returned, which defaults to 'inline' unless passed
161
     * something else.
162
     *
163
     * @param string $default Optional default value if not set or does not
164
     *        match 'inline' or 'attachment'.
165
     * @return string the content disposition
166
     */
167 97
    public function getContentDisposition(?string $default = 'inline') : ?string
168
    {
169 97
        $value = $this->getHeaderValue(HeaderConsts::CONTENT_DISPOSITION);
170 97
        if ($value === null || !\in_array($value, ['inline', 'attachment'])) {
171 95
            return $default;
172
        }
173 55
        return \strtolower($value);
174
    }
175
176
    /**
177
     * Returns the content transfer encoding used to encode the content on this
178
     * part, or the value of $default if not defined.
179
     *
180
     * Looks up and returns the value of the 'Content-Transfer-Encoding' header
181
     * if set, defaulting to '7bit' if an alternate $default param is not
182
     * passed.
183
     *
184
     * The returned value is always lowercase, and header values of 'x-uue',
185
     * 'uue' and 'uuencode' will return 'x-uuencode' instead.
186
     *
187
     * @param string $default Optional default value to return if the header
188
     *        isn't set.
189
     * @return string the content transfer encoding.
190
     */
191 104
    public function getContentTransferEncoding(?string $default = '7bit') : ?string
192
    {
193 104
        static $translated = [
194 104
            'x-uue' => 'x-uuencode',
195 104
            'uue' => 'x-uuencode',
196 104
            'uuencode' => 'x-uuencode'
197 104
        ];
198 104
        $type = \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TRANSFER_ENCODING, $default));
0 ignored issues
show
Bug introduced by
It seems like $this->getHeaderValue(ZB...FER_ENCODING, $default) can also be of type null; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

198
        $type = \strtolower(/** @scrutinizer ignore-type */ $this->getHeaderValue(HeaderConsts::CONTENT_TRANSFER_ENCODING, $default));
Loading history...
199 104
        if (isset($translated[$type])) {
200 2
            return $translated[$type];
201
        }
202 104
        return $type;
203
    }
204
205
    /**
206
     * Returns the Content ID of the part, or null if not defined.
207
     *
208
     * Looks up and returns the value of the 'Content-ID' header.
209
     *
210
     * @return string|null the content ID or null if not defined.
211
     */
212 3
    public function getContentId() : ?string
213
    {
214 3
        return $this->getHeaderValue(HeaderConsts::CONTENT_ID);
215
    }
216
217
    /**
218
     * Returns true if this part's parent is an IMessage, and is the same part
219
     * returned by {@see IMessage::getSignaturePart()}.
220
     *
221
     * @return bool
222
     */
223 57
    public function isSignaturePart()
224
    {
225 57
        if ($this->parent === null || !$this->parent instanceof IMessage) {
226 20
            return false;
227
        }
228 52
        return $this->parent->getSignaturePart() === $this;
229
    }
230
231 119
    public function getHeader($name, $offset = 0)
232
    {
233 119
        return $this->headerContainer->get($name, $offset);
234
    }
235
236 1
    public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
237
    {
238 1
        return $this->headerContainer->getAs($name, $iHeaderClass, $offset);
239
    }
240
241 20
    public function getAllHeaders()
242
    {
243 20
        return $this->headerContainer->getHeaderObjects();
244
    }
245
246 1
    public function getAllHeadersByName($name)
247
    {
248 1
        return $this->headerContainer->getAll($name);
249
    }
250
251 1
    public function getRawHeaders()
252
    {
253 1
        return $this->headerContainer->getHeaders();
254
    }
255
256 94
    public function getRawHeaderIterator()
257
    {
258 94
        return $this->headerContainer->getIterator();
259
    }
260
261 116
    public function getHeaderValue($name, $defaultValue = null)
262
    {
263 116
        $header = $this->getHeader($name);
264 116
        if ($header !== null) {
265 115
            return $header->getValue() ?: $defaultValue;
266
        }
267 106
        return $defaultValue;
268
    }
269
270 108
    public function getHeaderParameter($header, $param, $defaultValue = null)
271
    {
272 108
        $obj = $this->getHeader($header);
273 108
        if ($obj && $obj instanceof ParameterHeader) {
274 104
            return $obj->getValueFor($param, $defaultValue);
275
        }
276 13
        return $defaultValue;
277
    }
278
279
    /**
280
     * @return static
281
     */
282 23
    public function setRawHeader(string $name, ?string $value, int $offset = 0)
283
    {
284 23
        $this->headerContainer->set($name, $value, $offset);
285 23
        $this->notify();
286 23
        return $this;
287
    }
288
289
    /**
290
     * @return static
291
     */
292 1
    public function addRawHeader(string $name, string $value)
293
    {
294 1
        $this->headerContainer->add($name, $value);
295 1
        $this->notify();
296 1
        return $this;
297
    }
298
299
    /**
300
     * @return static
301
     */
302 19
    public function removeHeader(string $name)
303
    {
304 19
        $this->headerContainer->removeAll($name);
305 19
        $this->notify();
306 19
        return $this;
307
    }
308
309
    /**
310
     * @return static
311
     */
312 1
    public function removeSingleHeader(string $name, int $offset = 0)
313
    {
314 1
        $this->headerContainer->remove($name, $offset);
315 1
        $this->notify();
316 1
        return $this;
317
    }
318
}
319