Test Failed
Pull Request — master (#18)
by mon
01:52
created

TypeParser::parse()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 6
nop 2
dl 0
loc 37
ccs 22
cts 22
cp 1
crap 6
rs 8.9617
c 0
b 0
f 0
1
<?php
2
3
namespace FileEye\MimeMap;
4
5
/**
6
 * Class for parsing RFC 2045 Content-Type Header Fields.
7
 */
8
class TypeParser
9
{
10
    /**
11
     * Parse a mime-type and set the class variables.
12
     *
13
     * @param string $type_string
14
     *   MIME type string to parse.
15
     * @param Type $type
16
     *   The Type object to receive the components.
17
     *
18
     * @return void
19
     */
20 61
    public static function parse($type_string, Type $type)
21
    {
22 61
        if (is_null($type_string)) {
0 ignored issues
show
introduced by
The condition is_null($type_string) is always false.
Loading history...
23 1
            return;
24
        }
25
26
        // Media and SubType are separated by a slash '/'.
27 60
        $media = static::parseStringPart($type_string, 0, '/');
28
29 59
        if (!$media['string']) {
30 2
            throw new MalformedTypeException('Media type not found');
31
        }
32 57
        if (!$media['delimiter_matched']) {
33 1
            throw new MalformedTypeException('Slash \'/\' to separate media type and subtype not found');
34
        }
35
36 56
        $type->setMedia(strtolower($media['string']));
0 ignored issues
show
Bug introduced by
$media['string'] of type void is incompatible with the type string expected by parameter $str of strtolower(). ( Ignorable by Annotation )

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

36
        $type->setMedia(strtolower(/** @scrutinizer ignore-type */ $media['string']));
Loading history...
37 56
        $type->setMediaComment($media['comment']);
38
39
        // SubType and Parameters are separated by semicolons ';'.
40 56
        $sub = static::parseStringPart($type_string, $media['end_offset'] + 1, ';');
41
42 55
        if (!$sub['string']) {
43 1
            throw new MalformedTypeException('Media subtype not found');
44
        }
45
46 54
        $type->setSubType(strtolower($sub['string']));
47 54
        $type->setSubTypeComment($sub['comment']);
48
49
        // Loops through the parameter.
50 54
        while ($sub['delimiter_matched']) {
51 27
            $sub = static::parseStringPart($type_string, $sub['end_offset'] + 1, ';');
52 27
            $tmp = explode('=', $sub['string'], 2);
53 27
            $p_name = trim($tmp[0]);
54 27
            $p_val = trim($tmp[1]);
55 27
            $p_val = str_replace('\\"', '"', $p_val);
56 27
            $type->addParameter($p_name, $p_val, $sub['comment']);
57
        }
58 54
    }
59
60
    /**
61
     * Parses a part of the content MIME type string.
62
     *
63
     * Splits string and comment until a delimiter is found.
64
     *
65
     * @param string $string
66
     *   Input string.
67
     * @param int $offset
68
     *   Offset to start parsing from.
69
     * @param string $delimiter
70
     *   Stop parsing when delimiter found.
71
     *
72
     * @return array
73
     *   An array with the following keys:
74
     *   'string' - the uncommented part of $string
75
     *   'comment' - the comment part of $string
76
     *   'delimiter_matched' - true if a $delimiter stopped the parsing, false
77
     *                         otherwise
78
     *   'end_offset' - the last position parsed in $string.
79
     */
80 60
    public static function parseStringPart($string, $offset, $delimiter)
81
    {
82 60
        $inquote   = false;
83 60
        $escaped   = false;
84 60
        $incomment = 0;
85 60
        $newstring = '';
86 60
        $comment = '';
87
88 60
        for ($n = $offset; $n < strlen($string); $n++) {
89 59
            if ($string[$n] === $delimiter && !$escaped && !$inquote && $incomment === 0) {
90 57
                break;
91
            }
92
93 58
            if ($escaped) {
94 4
                if ($incomment == 0) {
95 2
                    $newstring .= $string[$n];
96
                } else {
97 2
                    $comment .= $string[$n];
98
                }
99 4
                $escaped = false;
100 4
                continue;
101
            }
102
103 58
            if ($string[$n] == '\\') {
104 4
                if ($incomment > 0) {
105 2
                    $comment .= $string[$n];
106
                }
107 4
                $escaped = true;
108 4
                continue;
109
            }
110
111 58
            if (!$inquote && $incomment > 0 && $string[$n] == ')') {
112 21
                $incomment--;
113 21
                if ($incomment == 0) {
114 19
                    $comment .= ' ';
115
                }
116 21
                continue;
117
            }
118
119 58
            if (!$inquote && $string[$n] == '(') {
120 21
                $incomment++;
121 21
                continue;
122
            }
123
124 58
            if ($string[$n] == '"') {
125 10
                if ($incomment > 0) {
126 1
                    $comment .= $string[$n];
127
                } else {
128 9
                    if ($inquote) {
129 9
                        $inquote = false;
130
                    } else {
131 9
                        $inquote = true;
132
                    }
133
                }
134 10
                continue;
135
            }
136
137 58
            if ($incomment == 0) {
138 58
                $newstring .= $string[$n];
139 58
                continue;
140
            }
141
142 21
            $comment .= $string[$n];
143
        }
144
145 60
        if ($incomment > 0) {
146 2
            throw new MalformedTypeException('Comment closing bracket missing: ' . $comment);
147
        }
148
149
        return [
150 59
          'string' => empty($newstring) ? null : trim($newstring),
0 ignored issues
show
introduced by
The condition empty($newstring) is always true.
Loading history...
151 59
          'comment' => empty($comment) ? null : trim($comment),
0 ignored issues
show
introduced by
The condition empty($comment) is always true.
Loading history...
152 59
          'delimiter_matched' => isset($string[$n]) ? ($string[$n] === $delimiter) : false,
153 59
          'end_offset' => $n,
154
        ];
155
    }
156
}
157