Passed
Pull Request — master (#372)
by
unknown
22:49
created

Header::normalizeValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 3
c 1
b 0
f 1
nc 2
nop 1
dl 0
loc 6
rs 10
1
<?php
2
3
namespace Qiniu\Http;
4
5
/**
6
 * field name case-insensitive Header
7
 */
8
class Header implements \ArrayAccess, \IteratorAggregate, \Countable
9
{
10
    /** @var array normalized key name map */
11
    private $data;
12
13
    /**
14
     * @param array $obj non-normalized header object
15
     */
16
    public function __construct($obj = array())
17
    {
18
        foreach ($obj as $key => $values) {
19
            $normalizedKey = self::normalizeKey($key);
20
            $normalizedValues = array();
21
            foreach ($values as $value) {
22
                array_push($normalizedValues, self::normalizeValue($value));
23
            }
24
            $this->data[$normalizedKey] = $normalizedValues;
25
        }
26
        return $this;
27
    }
28
29
    /**
30
     * return origin headers, which is field name case-sensitive
31
     *
32
     * @param string $raw
33
     *
34
     * @return array
35
     */
36
    public static function parseRawText($raw)
37
    {
38
        $headers = array();
39
        $headerLines = explode("\r\n", $raw);
40
        foreach ($headerLines as $line) {
41
            $headerLine = trim($line);
42
            $kv = explode(':', $headerLine);
43
            if (count($kv) <= 1) {
44
                continue;
45
            }
46
            // for http2 [Pseudo-Header Fields](https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.1)
47
            if ($kv[0] == "") {
48
                $fieldName = ":" . $kv[1];
49
            } else {
50
                $fieldName = $kv[0];
51
            }
52
            $fieldValue = trim(substr($headerLine, strlen($fieldName . ":")));
53
            if (isset($headers[$fieldName])) {
54
                array_push($headers[$fieldName], $fieldValue);
55
            } else {
56
                $headers[$fieldName] = array($fieldValue);
57
            }
58
        }
59
        return $headers;
60
    }
61
62
    /**
63
     * @param string $raw
64
     *
65
     * @return Header
66
     */
67
    public static function fromRawText($raw)
68
    {
69
        return new Header(self::parseRawText($raw));
70
    }
71
72
    /**
73
     * @param string $key
74
     *
75
     * @return string
76
     */
77
    public static function normalizeKey($key)
78
    {
79
        $key = trim($key);
80
81
        if (!self::isValidKeyName($key)) {
82
            return $key;
83
        }
84
85
        return ucwords(strtolower($key), '-');
86
    }
87
88
    /**
89
     * @param string | numeric $value
0 ignored issues
show
Bug introduced by
The type Qiniu\Http\numeric was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
90
     *
91
     * @return string | numeric
92
     */
93
    public static function normalizeValue($value)
94
    {
95
        if (is_numeric($value)) {
96
            return $value + 0;
97
        }
98
        return trim($value);
99
    }
100
101
    public function getRawData()
102
    {
103
        return $this->data;
104
    }
105
106
    public function offsetExists($offset)
107
    {
108
        $key = self::normalizeKey($offset);
109
        return isset($this->data[$key]);
110
    }
111
112
    public function offsetGet($offset)
113
    {
114
        $key = self::normalizeKey($offset);
115
        if (isset($this->data[$key]) && count($this->data[$key])) {
116
            return $this->data[$key][0];
117
        } else {
118
            return null;
119
        }
120
    }
121
122
    public function offsetSet($offset, $value)
123
    {
124
        $key = self::normalizeKey($offset);
125
        if (isset($this->data[$key]) && count($this->data[$key] > 0)) {
0 ignored issues
show
Bug introduced by
$this->data[$key] > 0 of type boolean is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

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

125
        if (isset($this->data[$key]) && count(/** @scrutinizer ignore-type */ $this->data[$key] > 0)) {
Loading history...
126
            $this->data[$key][0] = self::normalizeValue($value);
127
        } else {
128
            $this->data[$key] = array(self::normalizeValue($value));
129
        }
130
    }
131
132
    public function offsetUnset($offset)
133
    {
134
        $key = self::normalizeKey($offset);
135
        unset($this->data[$key]);
136
    }
137
138
    public function getIterator()
139
    {
140
        $arr = array();
141
        foreach ($this->data as $k => $v) {
142
            $arr[$k] = $v[0];
143
        }
144
        return new \ArrayIterator($arr);
145
    }
146
147
    public function count()
148
    {
149
        return count($this->data);
150
    }
151
152
153
    private static $isTokenTable = array(
154
        '!' => true,
155
        '#' => true,
156
        '$' => true,
157
        '%' => true,
158
        '&' => true,
159
        '\'' => true,
160
        '*' => true,
161
        '+' => true,
162
        '-' => true,
163
        '.' => true,
164
        '0' => true,
165
        '1' => true,
166
        '2' => true,
167
        '3' => true,
168
        '4' => true,
169
        '5' => true,
170
        '6' => true,
171
        '7' => true,
172
        '8' => true,
173
        '9' => true,
174
        'A' => true,
175
        'B' => true,
176
        'C' => true,
177
        'D' => true,
178
        'E' => true,
179
        'F' => true,
180
        'G' => true,
181
        'H' => true,
182
        'I' => true,
183
        'J' => true,
184
        'K' => true,
185
        'L' => true,
186
        'M' => true,
187
        'N' => true,
188
        'O' => true,
189
        'P' => true,
190
        'Q' => true,
191
        'R' => true,
192
        'S' => true,
193
        'T' => true,
194
        'U' => true,
195
        'W' => true,
196
        'V' => true,
197
        'X' => true,
198
        'Y' => true,
199
        'Z' => true,
200
        '^' => true,
201
        '_' => true,
202
        '`' => true,
203
        'a' => true,
204
        'b' => true,
205
        'c' => true,
206
        'd' => true,
207
        'e' => true,
208
        'f' => true,
209
        'g' => true,
210
        'h' => true,
211
        'i' => true,
212
        'j' => true,
213
        'k' => true,
214
        'l' => true,
215
        'm' => true,
216
        'n' => true,
217
        'o' => true,
218
        'p' => true,
219
        'q' => true,
220
        'r' => true,
221
        's' => true,
222
        't' => true,
223
        'u' => true,
224
        'v' => true,
225
        'w' => true,
226
        'x' => true,
227
        'y' => true,
228
        'z' => true,
229
        '|' => true,
230
        '~' => true,
231
    );
232
233
    /**
234
     * @param string $str
235
     *
236
     * @return boolean
237
     */
238
    private static function isValidKeyName($str)
239
    {
240
        for ($i = 0; $i < count($str); $i += 1) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Bug introduced by
$str of type string is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

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

240
        for ($i = 0; $i < count(/** @scrutinizer ignore-type */ $str); $i += 1) {
Loading history...
241
            if (!isset(self::$isTokenTable[$str[$i]])) {
242
                return false;
243
            }
244
        }
245
        return true;
246
    }
247
}
248