Test Failed
Push — master ( e258e4...a626ba )
by Zaahid
15:25
created

MimeToken::decodeMatchedEntity()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 10
c 2
b 0
f 0
dl 0
loc 14
rs 9.9332
cc 4
nc 8
nop 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\Header\Part;
9
10
use Psr\Log\LoggerInterface;
11
use ZBateson\MbWrapper\MbWrapper;
12
13
/**
14
 * Represents a single mime header part token, with the possibility of it being
15
 * MIME-Encoded as per RFC-2047.
16
 *
17
 * MimeToken automatically decodes the value if it's encoded.
18
 *
19
 * @author Zaahid Bateson
20
 */
21
class MimeToken extends Token
22
{
23
    /**
24
     * @var string regex pattern matching a mime-encoded part
25
     */
26
    public const MIME_PART_PATTERN = '=\?[^?=]+\?[QBqb]\?[^\?]+\?=';
27
28
    /**
29
     * @var string regex pattern used when parsing parameterized headers
30
     */
31
    public const MIME_PART_PATTERN_NO_QUOTES = '=\?[^\?=]+\?[QBqb]\?[^\?"]+\?=';
32
33
    /**
34
     * @var ?string the language code if any, or null otherwise
35
     */
36
    protected ?string $language = null;
37
38
    /**
39
     * @var ?string the charset if any, or null otherwise
40
     */
41
    protected ?string $charset = null;
42
43
    public function __construct(LoggerInterface $logger, MbWrapper $charsetConverter, string $value)
44
    {
45
        parent::__construct($logger, $charsetConverter, $value);
46
        $this->value = $this->decodeMime(\preg_replace('/\r|\n/', '', $this->value));
47
        $pattern = self::MIME_PART_PATTERN;
48
        $this->canIgnoreSpacesBefore = (bool) \preg_match("/^\s*{$pattern}|\s+/", $this->rawValue);
49
        $this->canIgnoreSpacesAfter = (bool) \preg_match("/{$pattern}\s*|\s+\$/", $this->rawValue);
50
    }
51
52
    /**
53
     * Finds and replaces mime parts with their values.
54
     *
55
     * The method splits the token value into an array on mime-part-patterns,
56
     * either replacing a mime part with its value by calling iconv_mime_decode
57
     * or converts the encoding on the text part by calling convertEncoding.
58
     */
59
    protected function decodeMime(string $value) : string
60
    {
61
        if (\preg_match('/^=\?([A-Za-z\-_0-9]+)\*?([A-Za-z\-_0-9]+)?\?([QBqb])\?([^\?]*)\?=$/', $value, $matches)) {
62
            return $this->decodeMatchedEntity($matches);
63
        }
64
        return $this->convertEncoding($value);
65
    }
66
67
    /**
68
     * Decodes a matched mime entity part into a string and returns it, after
69
     * adding the string into the languages array.
70
     *
71
     * @param string[] $matches
72
     */
73
    private function decodeMatchedEntity(array $matches) : string
74
    {
75
        $body = $matches[4];
76
        if (\strtoupper($matches[3]) === 'Q') {
77
            $body = \quoted_printable_decode(\str_replace('_', '=20', $body));
78
        } else {
79
            $body = \base64_decode($body);
80
        }
81
        $this->charset = $matches[1];
82
        $this->language = (!empty($matches[2])) ? $matches[2] : null;
83
        if ($this->charset !== null) {
84
            return $this->convertEncoding($body, $this->charset, true);
85
        }
86
        return $this->convertEncoding($body, 'ISO-8859-1', true);
87
    }
88
89
    /**
90
     * Returns the language code for the mime part.
91
     */
92
    public function getLanguage() : ?string
93
    {
94
        return $this->language;
95
    }
96
97
    /**
98
     * Returns the charset for the encoded part.
99
     */
100
    public function getCharset() : ?string
101
    {
102
        return $this->charset;
103
    }
104
105
    public function getRawValue() : string
106
    {
107
        return $this->rawValue;
108
    }
109
}
110