Passed
Push — master ( 46ed75...ca2387 )
by Zaahid
03:33
created

MimePart::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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

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

217
        return $this->parent->/** @scrutinizer ignore-call */ getSignaturePart() === $this;
Loading history...
218
    }
219
220 119
    public function getHeader($name, $offset = 0) : ?IHeader
221
    {
222 119
        return $this->headerContainer->get($name, $offset);
223
    }
224
225 1
    public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
226
    {
227 1
        return $this->headerContainer->getAs($name, $iHeaderClass, $offset);
228
    }
229
230 20
    public function getAllHeaders() : array
231
    {
232 20
        return $this->headerContainer->getHeaderObjects();
233
    }
234
235 1
    public function getAllHeadersByName($name) : array
236
    {
237 1
        return $this->headerContainer->getAll($name);
238
    }
239
240 1
    public function getRawHeaders() : array
241
    {
242 1
        return $this->headerContainer->getHeaders();
243
    }
244
245 94
    public function getRawHeaderIterator() : Traversable
246
    {
247 94
        return $this->headerContainer->getIterator();
248
    }
249
250 116
    public function getHeaderValue($name, $defaultValue = null) : ?string
251
    {
252 116
        $header = $this->getHeader($name);
253 116
        if ($header !== null) {
254 115
            return $header->getValue() ?: $defaultValue;
255
        }
256 106
        return $defaultValue;
257
    }
258
259 108
    public function getHeaderParameter($header, $param, $defaultValue = null) : ?string
260
    {
261 108
        $obj = $this->getHeader($header);
262 108
        if ($obj && $obj instanceof ParameterHeader) {
263 104
            return $obj->getValueFor($param, $defaultValue);
264
        }
265 13
        return $defaultValue;
266
    }
267
268 23
    public function setRawHeader(string $name, ?string $value, int $offset = 0) : static
269
    {
270 23
        $this->headerContainer->set($name, $value, $offset);
271 23
        $this->notify();
272 23
        return $this;
273
    }
274
275 1
    public function addRawHeader(string $name, string $value) : static
276
    {
277 1
        $this->headerContainer->add($name, $value);
278 1
        $this->notify();
279 1
        return $this;
280
    }
281
282 19
    public function removeHeader(string $name) : static
283
    {
284 19
        $this->headerContainer->removeAll($name);
285 19
        $this->notify();
286 19
        return $this;
287
    }
288
289 1
    public function removeSingleHeader(string $name, int $offset = 0) : static
290
    {
291 1
        $this->headerContainer->remove($name, $offset);
292 1
        $this->notify();
293 1
        return $this;
294
    }
295
296
    public function getErrorBagChildren(): array
297
    {
298
        return \array_merge([ $this->headerContainer ], parent::getErrorBagChildren());
299
    }
300
}
301