Header::isValidKeyName()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 4
c 1
b 0
f 1
nc 3
nop 1
dl 0
loc 8
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 = array();
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
            if (!is_array($values)) {
22
                array_push(
23
                    $normalizedValues,
24
                    self::normalizeValue($values)
25
                );
26
            } else {
27
                foreach ($values as $value) {
28
                    array_push(
29
                        $normalizedValues,
30
                        self::normalizeValue($value)
31
                    );
32
                }
33
            }
34
            $this->data[$normalizedKey] = $normalizedValues;
35
        }
36
        return $this;
37
    }
38
39
    /**
40
     * return origin headers, which is field name case-sensitive
41
     *
42
     * @param string $raw
43
     *
44
     * @return array
45
     */
46
    public static function parseRawText($raw)
47
    {
48
        $multipleHeaders = explode("\r\n\r\n", trim($raw));
49
        $headers = array();
50
        $headerLines = explode("\r\n", end($multipleHeaders));
51
        foreach ($headerLines as $line) {
52
            $headerLine = trim($line);
53
            $kv = explode(':', $headerLine);
54
            if (count($kv) <= 1) {
55
                continue;
56
            }
57
            // for http2 [Pseudo-Header Fields](https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.1)
58
            if ($kv[0] == "") {
59
                $fieldName = ":" . $kv[1];
60
            } else {
61
                $fieldName = $kv[0];
62
            }
63
            $fieldValue = trim(substr($headerLine, strlen($fieldName . ":")));
64
            if (isset($headers[$fieldName])) {
65
                array_push($headers[$fieldName], $fieldValue);
66
            } else {
67
                $headers[$fieldName] = array($fieldValue);
68
            }
69
        }
70
        return $headers;
71
    }
72
73
    /**
74
     * @param string $raw
75
     *
76
     * @return Header
77
     */
78
    public static function fromRawText($raw)
79
    {
80
        return new Header(self::parseRawText($raw));
81
    }
82
83
    /**
84
     * @param string $key
85
     *
86
     * @return string
87
     */
88
    public static function normalizeKey($key)
89
    {
90
        $key = trim($key);
91
92
        if (!self::isValidKeyName($key)) {
93
            return $key;
94
        }
95
96
        return \Qiniu\ucwords(strtolower($key), '-');
97
    }
98
99
    /**
100
     * @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...
101
     *
102
     * @return string|numeric
103
     */
104
    public static function normalizeValue($value)
105
    {
106
        if (is_numeric($value)) {
107
            return $value + 0;
108
        }
109
        return trim($value);
110
    }
111
112
    /**
113
     * @return array
114
     */
115
    public function getRawData()
116
    {
117
        return $this->data;
118
    }
119
120
    /**
121
     * @param $offset string
122
     *
123
     * @return boolean
124
     */
125
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
126
    public function offsetExists($offset)
127
    {
128
        $key = self::normalizeKey($offset);
129
        return isset($this->data[$key]);
130
    }
131
132
    /**
133
     * @param $offset string
134
     *
135
     * @return string|null
136
     */
137
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
138
    public function offsetGet($offset)
139
    {
140
        $key = self::normalizeKey($offset);
141
        if (isset($this->data[$key]) && count($this->data[$key])) {
142
            return $this->data[$key][0];
143
        } else {
144
            return null;
145
        }
146
    }
147
148
    /**
149
     * @param $offset string
150
     * @param $value string
151
     *
152
     * @return void
153
     */
154
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
155
    public function offsetSet($offset, $value)
156
    {
157
        $key = self::normalizeKey($offset);
158
        if (isset($this->data[$key]) && count($this->data[$key]) > 0) {
159
            $this->data[$key][0] = self::normalizeValue($value);
160
        } else {
161
            $this->data[$key] = array(self::normalizeValue($value));
162
        }
163
    }
164
165
    /**
166
     * @return void
167
     */
168
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
169
    public function offsetUnset($offset)
170
    {
171
        $key = self::normalizeKey($offset);
172
        unset($this->data[$key]);
173
    }
174
175
    /**
176
     * @return \ArrayIterator
177
     */
178
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
179
    public function getIterator()
180
    {
181
        $arr = array();
182
        foreach ($this->data as $k => $v) {
183
            $arr[$k] = $v[0];
184
        }
185
        return new \ArrayIterator($arr);
186
    }
187
188
    /**
189
     * @return int
190
     */
191
    #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x
192
    public function count()
193
    {
194
        return count($this->data);
195
    }
196
197
    private static $isTokenTable = array(
198
        '!' => true,
199
        '#' => true,
200
        '$' => true,
201
        '%' => true,
202
        '&' => true,
203
        '\'' => true,
204
        '*' => true,
205
        '+' => true,
206
        '-' => true,
207
        '.' => true,
208
        '0' => true,
209
        '1' => true,
210
        '2' => true,
211
        '3' => true,
212
        '4' => true,
213
        '5' => true,
214
        '6' => true,
215
        '7' => true,
216
        '8' => true,
217
        '9' => true,
218
        'A' => true,
219
        'B' => true,
220
        'C' => true,
221
        'D' => true,
222
        'E' => true,
223
        'F' => true,
224
        'G' => true,
225
        'H' => true,
226
        'I' => true,
227
        'J' => true,
228
        'K' => true,
229
        'L' => true,
230
        'M' => true,
231
        'N' => true,
232
        'O' => true,
233
        'P' => true,
234
        'Q' => true,
235
        'R' => true,
236
        'S' => true,
237
        'T' => true,
238
        'U' => true,
239
        'W' => true,
240
        'V' => true,
241
        'X' => true,
242
        'Y' => true,
243
        'Z' => true,
244
        '^' => true,
245
        '_' => true,
246
        '`' => true,
247
        'a' => true,
248
        'b' => true,
249
        'c' => true,
250
        'd' => true,
251
        'e' => true,
252
        'f' => true,
253
        'g' => true,
254
        'h' => true,
255
        'i' => true,
256
        'j' => true,
257
        'k' => true,
258
        'l' => true,
259
        'm' => true,
260
        'n' => true,
261
        'o' => true,
262
        'p' => true,
263
        'q' => true,
264
        'r' => true,
265
        's' => true,
266
        't' => true,
267
        'u' => true,
268
        'v' => true,
269
        'w' => true,
270
        'x' => true,
271
        'y' => true,
272
        'z' => true,
273
        '|' => true,
274
        '~' => true,
275
    );
276
277
    /**
278
     * @param string $str
279
     *
280
     * @return boolean
281
     */
282
    private static function isValidKeyName($str)
283
    {
284
        for ($i = 0; $i < strlen($str); $i += 1) {
285
            if (!isset(self::$isTokenTable[$str[$i]])) {
286
                return false;
287
            }
288
        }
289
        return true;
290
    }
291
}
292