Request::header()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace MinasRouter\Http;
4
5
class Request
6
{
7
    private $fullUrl;
8
9
    private $httpMethod;
10
11
    private $data = [];
12
13
    private $queryStrings;
14
15
    private $params;
16
17
    private $headers;
18
19
    public function __construct(
20
        String $fullUrl,
21
        String $route,
22
        array $routeParams
23
    ) {
24
        $this->fullUrl = $fullUrl . ($_SERVER['REQUEST_URI'] ?? '/');
25
26
        $this->httpMethod = $_SERVER['REQUEST_METHOD'] ?? '';
27
        $this->queryStrings = $_GET;
28
29
        if (isset($this->queryStrings["route"])) {
30
            unset($this->queryStrings["route"]);
31
        }
32
33
        $this->headers = $this->resolveHeaders();
34
35
        $this->resolveRouteData($route, $routeParams);
36
37
        if ($this->httpMethod != 'GET') {
38
            $this->setData();
39
        }
40
    }
41
42
    /**
43
     * Method responsible for bringing
44
     * all request headers.
45
     * 
46
     * @return array
47
     */
48
    protected function resolveHeaders()
49
    {
50
        $headers = [];
51
52
        foreach ($_SERVER as $name => $value) {
53
            if (substr($name, 0, 5) == 'HTTP_') {
54
                $index = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
55
                $headers[$index] = $value;
56
            }
57
        }
58
59
        return $headers;
60
    }
61
62
    /**
63
     * Method responsible for returning the
64
     * current route in parts.
65
     * 
66
     * @return string|null|array
67
     */
68
    protected function getParsedRoute(?String $data = null)
69
    {
70
        $parsedRoute = parse_url($this->fullUrl ?? "/");
71
72
        if (empty($data)) return $parsedRoute;
73
74
        if (isset($parsedRoute[$data])) {
75
            return $parsedRoute[$data];
76
        }
77
78
        return null;
79
    }
80
81
    /**
82
     * Method responsible for returning
83
     * the current route path.
84
     * 
85
     * @return string
86
     */
87
    public function path()
88
    {
89
        $path = $this->getParsedRoute("path");
90
91
        return $path ?? "/";
0 ignored issues
show
Bug Best Practice introduced by
The expression return $path ?? '/' also could return the type array which is incompatible with the documented return type string.
Loading history...
92
    }
93
94
    /**
95
     * Method responsible for returning
96
     * the current route without query strings.
97
     * 
98
     * @return null|string
99
     */
100
    public function url()
101
    {
102
        $path = $this->getParsedRoute();
103
104
        if (!$path) return null;
105
106
        return "{$path['scheme']}://{$path['host']}{$this->path()}";
107
    }
108
109
    /**
110
     * Method responsible for returning
111
     * the full current route (with query strings).
112
     * 
113
     * @return null|string
114
     */
115
    public function fullUrl()
116
    {
117
        $query = $this->getParsedRoute("query");
118
119
        return "{$this->url()}?{$query}";
120
    }
121
122
    /**
123
     * Method responsible for returning the
124
     * route's dynamic parameters.
125
     * 
126
     * @return array
127
     */
128
    public function getParams()
129
    {
130
        return $this->params;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->params also could return the type mixed which is incompatible with the documented return type array.
Loading history...
131
    }
132
133
    /**
134
     * Method responsible for returning one or all
135
     * data coming from the params query ($_GET).
136
     * 
137
     * @param null|string $name = null
138
     * @param null|string $asDefault = null
139
     * 
140
     * @return array|string
141
     */
142
    public function query(?String $name = null, ?String $asDefault = null)
143
    {
144
        if (!$name) {
145
            return $this->queryStrings;
146
        }
147
148
        if (isset($this->queryStrings[$name])) {
149
            return $this->queryStrings[$name];
150
        }
151
152
        return $asDefault;
153
    }
154
155
    /**
156
     * Returns a property that does not exist in the class,
157
     * usually they are indexes of the route array. Returns null
158
     * if this index/property does not exist.
159
     * 
160
     * @param string $data
161
     * 
162
     * @return string|null|array
163
     */
164
    public function __get(String $data)
165
    {
166
        if (isset($this->data[$data])) {
167
            return $this->data[$data];
168
        }
169
170
        if (isset($this->queryStrings[$data])) {
171
            return $this->queryStrings[$data];
172
        }
173
174
        if (isset($this->params[$data])) {
175
            return $this->params[$data];
176
        }
177
178
        return null;
179
    }
180
181
    /**
182
     * Method responsible for defining route data
183
     * 
184
     * @param string $route
185
     * @param array $routeParams
186
     * 
187
     * @return void
188
     */
189
    protected function resolveRouteData(String $route, array $routeParams): void
190
    {
191
        $params = (string) $this->path();
192
193
        $diff = array_diff(explode('/', $params), explode('/', $route));
194
195
        $diff = array_values($diff);
196
197
        if (!empty($diff)) {
198
            foreach ($routeParams as $index => $param) {
199
                if (!isset($diff[$index])) {
200
                    continue;
201
                }
202
203
                $this->params[$param] = rawurldecode($diff[$index]);
204
            }
205
        }
206
207
        if (empty($this->data)) {
208
            $this->data = [];
209
        }
210
211
        if (empty($this->params)) {
212
            $this->params = [];
213
        }
214
    }
215
216
    /**
217
     * Method responsible for assigning and handling
218
     * the data coming from the web form.
219
     * 
220
     * @return void
221
     */
222
    protected function setData()
223
    {
224
        $enableFormSpoofing = ["PUT", "PATCH", "DELETE"];
225
226
        $post = filter_input_array(INPUT_POST, FILTER_DEFAULT);
227
228
        if (!empty($post['_method']) && in_array($post['_method'], $enableFormSpoofing)) {
229
            $this->httpMethod = $post['_method'];
230
            $this->data = $post;
231
232
            unset($this->data["_method"]);
233
            return;
234
        }
235
        if ($this->httpMethod == "POST") {
236
            $this->data = filter_input_array(INPUT_POST, FILTER_DEFAULT);
237
238
            unset($this->data["_method"]);
239
            return;
240
        }
241
242
        if (in_array($this->httpMethod, $enableFormSpoofing) && !empty($_SERVER['CONTENT_LENGTH'])) {
243
            parse_str(file_get_contents('php://input', false, null, 0, $_SERVER['CONTENT_LENGTH']), $putPatch);
244
            $this->data = $putPatch;
245
246
            unset($this->data["_method"]);
247
            return;
248
        }
249
250
        $this->data = [];
251
        return;
252
    }
253
254
    /**
255
     * Return the httpMethod.
256
     * 
257
     * @return string
258
     */
259
    public function getMethod()
260
    {
261
        return $this->httpMethod;
262
    }
263
264
    /**
265
     * Method responsible for checking if the current http method
266
     * is the expected.
267
     * 
268
     * @param string $expectedMethod
269
     * 
270
     * @return bool
271
     */
272
    public function isMethod(String $expectedMethod): bool
273
    {
274
        return $this->getMethod() === $expectedMethod;
275
    }
276
277
    /**
278
     * Method responsible for returning all request data.
279
     * 
280
     * @param null|string $except = null
281
     * 
282
     * @return array|null
283
     */
284
    public function all(?String $except = null)
285
    {
286
        if (!$except) {
287
            return $this->data;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->data also could return the type mixed which is incompatible with the documented return type array|null.
Loading history...
288
        }
289
290
        $allWithExcession = $this->data;
291
        $except = explode(',', $except);
292
293
        $except = array_map(function ($excession) {
294
            return trim(rtrim($excession));
295
        }, $except);
296
297
        foreach ($except as $excession) {
298
            if (!isset($this->data[$excession])) return;
299
300
            unset($allWithExcession[$excession]);
301
        }
302
303
        return $allWithExcession;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $allWithExcession also could return the type mixed which is incompatible with the documented return type array|null.
Loading history...
304
    }
305
306
    /**
307
     * Method responsible for returning all header data.
308
     * 
309
     * @return array
310
     */
311
    public function getHeaders()
312
    {
313
        return $this->headers;
314
    }
315
316
    /**
317
     * Method responsible for returning one header data or default value.
318
     * 
319
     * @param string $header
320
     * @param null|string $asDefault
321
     * 
322
     * @return null|string
323
     */
324
    public function header(String $header, ?String $asDefault = null)
325
    {
326
        if (isset($this->headers[$header])) {
327
            return $this->headers[$header];
328
        }
329
330
        return $asDefault;
331
    }
332
333
    /**
334
     * Method responsible for checking if there is one
335
     * header in the request.
336
     * 
337
     * @param string $header
338
     * 
339
     * @return bool
340
     */
341
    public function hasHeader(String $header)
342
    {
343
        return (bool) $this->header($header);
344
    }
345
346
    /**
347
     * Method responsible for returning ip of client request.
348
     * 
349
     * @return string
350
     */
351
    public function ip()
352
    {
353
        if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
354
            if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') > 0) {
355
                $addr = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);
356
                return trim($addr[0]);
357
            } else {
358
                return $_SERVER['HTTP_X_FORWARDED_FOR'];
359
            }
360
        } else {
361
            return $_SERVER['REMOTE_ADDR'];
362
        }
363
    }
364
365
    /**
366
     * Return the bearer token.
367
     * 
368
     * @return null|string
369
     */
370
    public function bearerToken()
371
    {
372
        $authorizationHeader = $this->header('Authorization');
373
374
        if (!$authorizationHeader) return null;
375
376
        if (preg_match("/^Bearer\s(.*)+$/", $authorizationHeader, $found)) {
377
            return $authorizationHeader;
378
        }
379
380
        return null;
381
    }
382
}
383