Passed
Push — master ( 2a5c20...8a2ae8 )
by Zaahid
07:05
created

ParameterConsumer::getPartForToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
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\Token;
10
use ZBateson\MailMimeParser\Header\Part\MimeLiteralPart;
11
use ZBateson\MailMimeParser\Header\Part\SplitParameterToken;
12
use ArrayObject;
13
14
/**
15
 * Reads headers separated into parameters consisting of a main value, and
16
 * subsequent name/value pairs - for example text/html; charset=utf-8.
17
 * 
18
 * A ParameterConsumer's parts are separated by a semi-colon.  Its name/value
19
 * pairs are separated with an '=' character.
20
 * 
21
 * Parts may be mime-encoded entities.  Additionally, a value can be quoted and
22
 * comments may exist.
23
 * 
24
 * @author Zaahid Bateson
25
 */
26
class ParameterConsumer extends GenericConsumer
27
{
28
    /**
29
     * Returns semi-colon and equals char as token separators.
30
     * 
31
     * @return string[]
32
     */
33 16
    protected function getTokenSeparators()
34
    {
35 16
        return [';', '='];
36
    }
37
38
    /**
39
     * Returns a regex pattern used to split the input header string.  The
40
     * default implementation calls getAllTokenSeparators and implodes the
41
     * returned array with the regex OR '|' character as its glue.
42
     *
43
     * @return string the regex pattern
44
     */
45 16
    protected function getTokenSplitPattern()
46
    {
47 16
        $sChars = implode('|', $this->getAllTokenSeparators());
48 16
        $mimePartPattern = MimeLiteralPart::MIME_PART_PATTERN_NO_QUOTES;
49 16
        return '~(' . $mimePartPattern . '|\\\\.|' . $sChars . ')~';
50
    }
51
52
    /**
53
     * Creates and returns a \ZBateson\MailMimeParser\Header\Part\Token out of
54
     * the passed string token and returns it, unless the token is an escaped
55
     * literal, in which case a LiteralPart is returned.
56
     * 
57
     * @param string $token
58
     * @param bool $isLiteral
59
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart
60
     */
61 16
    protected function getPartForToken($token, $isLiteral)
62
    {
63 16
        if ($isLiteral) {
64 1
            return $this->partFactory->newLiteralPart($token);
65
        }
66 16
        return $this->partFactory->newToken($token);
67
    }
68
    
69
    /**
70
     * Adds the passed parameter with the given name and value to a
71
     * SplitParameterToken, at the passed index. If one with the given name
72
     * doesn't exist, it is created.
73
     * 
74
     * @param ArrayObject $splitParts
75
     * @param string $name
76
     * @param string $value
77
     * @param int $index
78
     * @param boolean $isEncoded
79
     */
80 11
    private function addToSplitPart(ArrayObject $splitParts, $name, $value, $index, $isEncoded)
81
    {
82 11
        $ret = null;
83 11
        if (!isset($splitParts[trim($name)])) {
84 11
            $ret = $this->partFactory->newSplitParameterToken($name);
85 11
            $splitParts[$name] = $ret;
86
        }
87 11
        $splitParts[$name]->addPart($value, $isEncoded, $index);
88 11
        return $ret;
89
    }
90
    
91
    /**
92
     * Instantiates and returns either a MimeLiteralPart if $strName is empty,
93
     * a SplitParameterToken if the parameter is a split parameter and is the
94
     * first in a series, null if it's a split parameter but is not the first
95
     * part in its series, or a ParameterPart is returned otherwise.
96
     * 
97
     * If the part is a SplitParameterToken, it's added to the passed
98
     * $splitParts as well with its name as a key.
99
     * 
100
     * @param string $strName
101
     * @param string $strValue
102
     * @param ArrayObject $splitParts
103
     * @return \ZBateson\MailMimeParser\Header\Part\MimeLiteralPart
104
     *         |SplitParameterToken|\ZBateson\MailMimeParser\Header\Part\ParameterPart
105
     */
106 16
    private function getPartFor($strName, $strValue, ArrayObject $splitParts)
107
    {
108 16
        if ($strName === '') {
109 16
            return $this->partFactory->newMimeLiteralPart($strValue);
110 16
        } elseif (preg_match('~^\s*([^\*]+)\*(\d*)(\*)?$~', $strName, $matches)) {
111 11
            return $this->addToSplitPart(
112 11
                $splitParts,
113 11
                $matches[1],
114 11
                $strValue,
115 11
                $matches[2],
116 11
                (empty($matches[2]) || !empty($matches[3]))
117
            );
118
        }
119 5
        return $this->partFactory->newParameterPart($strName, $strValue);
120
    }
121
122
    /**
123
     * Handles parameter separator tokens during final processing.
124
     * 
125
     * If the end token is found, a new HeaderPart is assigned to the passed
126
     * $combined array.  If an '=' character is found, $strCat is assigned to
127
     * $strName and emptied.
128
     * 
129
     * Returns true if the token was processed, and false otherwise.
130
     * 
131
     * @param string $tokenValue
132
     * @param ArrayObject $combined
133
     * @param ArrayObject $splitParts
134
     * @param string $strName
135
     * @param string $strCat
136
     * @return boolean
137
     */
138 16
    private function processTokenPart(
139
        $tokenValue,
140
        ArrayObject $combined,
141
        ArrayObject $splitParts,
142
        &$strName,
143
        &$strCat
144
    ) {
145 16
        if ($tokenValue === ';') {
146 16
            $combined[] = $this->getPartFor($strName, $strCat, $splitParts);
147 16
            $strName = '';
148 16
            $strCat = '';
149 16
            return true;
150 16
        } elseif ($tokenValue === '=' && $strCat !== '') {
151 16
            $strName = $strCat;
152 16
            $strCat = '';
153 16
            return true;
154
        }
155 16
        return false;
156
    }
157
    
158
    /**
159
     * Loops over parts in the passed array, creating ParameterParts out of any
160
     * parsed SplitParameterTokens, replacing them in the array.
161
     * 
162
     * The method then calls filterIgnoreSpaces to filter out empty elements in
163
     * the combined array and returns an array.
164
     * 
165
     * @param ArrayObject $combined
166
     * @return HeaderPart[]|array
167
     */
168 16
    private function finalizeParameterParts(ArrayObject $combined)
169
    {
170 16
        foreach ($combined as $key => $part) {
171 16
            if ($part instanceof SplitParameterToken) {
172 11
                $combined[$key] = $this->partFactory->newParameterPart(
173 11
                    $part->getName(),
174 11
                    $part->getValue(),
175 16
                    $part->getLanguage()
176
                );
177
            }
178
        }
179 16
        return $this->filterIgnoredSpaces($combined->getArrayCopy());
180
    }
181
    
182
    /**
183
     * Post processing involves creating Part\LiteralPart or Part\ParameterPart
184
     * objects out of created Token and LiteralParts.
185
     * 
186
     * @param HeaderPart[] $parts
187
     * @return HeaderPart[]|array
188
     */
189 16
    protected function processParts(array $parts)
190
    {
191 16
        $combined = new ArrayObject();
192 16
        $splitParts = new ArrayObject();
193 16
        $strCat = '';
194 16
        $strName = '';
195 16
        $parts[] = $this->partFactory->newToken(';');
196 16
        foreach ($parts as $part) {
197 16
            $pValue = $part->getValue();
198 16
            if ($part instanceof Token && $this->processTokenPart($pValue, $combined, $splitParts, $strName, $strCat)) {
199 16
                continue;
200
            }
201 16
            $strCat .= $pValue;
202
        }
203 16
        return $this->finalizeParameterParts($combined);
204
    }
205
}
206