Passed
Push — master ( 9e6d2f...c6b62f )
by Zaahid
06:54
created

extractMetaInformationAndValue()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 6
nc 6
nop 2
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
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\Part;
8
9
use ZBateson\StreamDecorators\Util\CharsetConverter;
10
11
/**
12
 * Holds a running value for an RFC-2231 split header parameter.
13
 * 
14
 * ParameterConsumer creates SplitParameterTokens when a split header parameter
15
 * is first found, and adds subsequent split parts to an already created one if
16
 * the parameter name matches.
17
 *
18
 * @author Zaahid Bateson
19
 */
20
class SplitParameterToken extends HeaderPart
21
{
22
    /**
23
     * @var string name of the parameter.
24
     */
25
    protected $name;
26
27
    /**
28
     * @var string[] keeps encoded parts values that need to be decoded.  Keys
29
     *      are set to the index part of the split parameter and used for
30
     *      sorting before decoding/concatenating.
31
     */
32
    protected $encodedParts = [];
33
34
    /**
35
     * @var string contains literal parts that don't require any decoding (and
36
     *      are therefore ISO-8859-1 (technically should be 7bit US-ASCII but
37
     *      allowing 8bit shouldn't be an issue as elsewhere in MMP).
38
     */
39
    protected $literalParts = [];
40
41
    /**
42
     * @var string RFC-1766 (or subset) language code with optional subtags,
43
     *      regions, etc...
44
     */
45
    protected $language;
46
47
    /**
48
     * @var string charset of content in $encodedParts.
49
     */
50
    protected $charset = 'ISO-8859-1';
51
52
    /**
53
     * Initializes a SplitParameterToken.
54
     * 
55
     * @param CharsetConverter $charsetConverter
56
     * @param string $name the parameter's name
57
     */
58 13
    public function __construct(CharsetConverter $charsetConverter, $name)
59
    {
60 13
        parent::__construct($charsetConverter, '');
0 ignored issues
show
Unused Code introduced by
The call to ZBateson\MailMimeParser\...aderPart::__construct() has too many arguments starting with ''. ( Ignorable by Annotation )

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

60
        parent::/** @scrutinizer ignore-call */ 
61
                __construct($charsetConverter, '');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
61 13
        $this->name = trim($name);
62 13
    }
63
64
    /**
65
     * Extracts charset and language from an encoded value, setting them on the
66
     * current object if $index is 0 and adds the value part to the encodedParts
67
     * array.
68
     * 
69
     * @param string $value
70
     * @param int $index
71
     */
72 9
    protected function extractMetaInformationAndValue($value, $index)
73
    {
74 9
        if (preg_match('~^([^\']*)\'([^\']*)\'(.*)$~', $value, $matches)) {
75 6
            if ($index === 0) {
76 6
                $this->charset = (!empty($matches[1])) ? $matches[1] : $this->charset;
77 6
                $this->language = (!empty($matches[2])) ? $matches[2] : $this->language;
78
            }
79 6
            $value = $matches[3];
80
        }
81 9
        $this->encodedParts[$index] = $value;
82 9
    }
83
    
84
    /**
85
     * Adds the passed part to the running array of values.
86
     * 
87
     * If $isEncoded is true, language and charset info is extracted from the
88
     * value, and the value is decoded before returning in getValue.
89
     * 
90
     * The value of the parameter is sorted based on the passed $index
91
     * arguments when adding before concatenating when re-constructing the
92
     * value.
93
     * 
94
     * @param string $value
95
     * @param boolean $isEncoded
96
     * @param int $index
97
     */
98 12
    public function addPart($value, $isEncoded, $index)
99
    {
100 12
        if (empty($index)) {
101 12
            $index = 0;
102
        }
103 12
        if ($isEncoded) {
104 9
            $this->extractMetaInformationAndValue($value, $index);
105
        } else {
106 5
            $this->literalParts[$index] = $this->convertEncoding($value);
107
        }
108 12
    }
109
    
110
    /**
111
     * Traverses $this->encodedParts until a non-sequential key is found, or the
112
     * end of the array is found.
113
     * 
114
     * This allows encoded parts of a split parameter to be split anywhere and
115
     * reconstructed.
116
     * 
117
     * The returned string is converted to UTF-8 before being returned.
118
     * 
119
     * @return string
120
     */
121 7
    private function getNextEncodedValue()
122
    {
123 7
        $cur = current($this->encodedParts);
124 7
        $key = key($this->encodedParts);
125 7
        $running = '';
126 7
        while ($cur !== false) {
127 7
            $running .= $cur;
128 7
            $cur = next($this->encodedParts);
129 7
            $nKey = key($this->encodedParts);
130 7
            if ($nKey !== $key + 1) {
131 7
                break;
132
            }
133 6
            $key = $nKey;
134
        }
135 7
        return $this->convertEncoding(
136 7
            rawurldecode($running),
137 7
            $this->charset,
138 7
            true
139
        );
140
    }
141
    
142
    /**
143
     * Reconstructs the value of the split parameter into a single UTF-8 string
144
     * and returns it.
145
     * 
146
     * @return string
147
     */
148 10
    public function getValue()
149
    {
150 10
        $parts = $this->literalParts;
151
        
152 10
        reset($this->encodedParts);
153 10
        ksort($this->encodedParts);
154 10
        while (current($this->encodedParts) !== false) {
155 7
            $parts[key($this->encodedParts)] = $this->getNextEncodedValue();
156
        }
157
        
158 10
        ksort($parts);
0 ignored issues
show
Bug introduced by
$parts of type string is incompatible with the type array expected by parameter $array of ksort(). ( Ignorable by Annotation )

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

158
        ksort(/** @scrutinizer ignore-type */ $parts);
Loading history...
159 10
        return array_reduce(
160 10
            $parts,
161 10
            function ($carry, $item) {
162 10
                return $carry . $item;
163 10
            },
164 10
            ''
165
        );
166
    }
167
    
168
    /**
169
     * Returns the name of the parameter.
170
     * 
171
     * @return string
172
     */
173 1
    public function getName()
174
    {
175 1
        return $this->name;
176
    }
177
    
178
    /**
179
     * Returns the language of the parameter if set, or null if not.
180
     * 
181
     * @return string
182
     */
183 5
    public function getLanguage()
184
    {
185 5
        return $this->language;
186
    }
187
}
188