Test Failed
Push — master ( b9b2d3...0317fe )
by Mikael
04:04
created

Request::getScriptName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Anax\Request;
4
5
/**
6
 * Storing information from the request and calculating related essentials.
7
 *
8
 */
9
class Request
10
{
11
    /**
12
     * @var string $requestUri Request URI from $_SERVER.
13
     * @var string $scriptName Scriptname from $_SERVER, actual scriptname part.
14
     * @var string $path       Scriptname from $_SERVER, path-part.
15
     */
16
    private $requestUri;
17
    private $scriptName;
18
    private $path;
19
20
21
22
    /**
23
     * @var string $route      The route.
24
     * @var array  $routeParts The route as an array.
25
     */
26
    private $route;
27
    private $routeParts;
28
29
30
31
    /**
32
     * @var string $currentUrl Current url.
33
     * @var string $siteUrl    Url to this site, http://dbwebb.se.
34
     * @var string $baseUrl    Url to root dir,
35
     *                         siteUrl . /some/installation/directory/.
36
     */
37
    private $currentUrl;
38
    private $siteUrl;
39
    private $baseUrl;
40
41
42
43
    /**
44
     * @var array $server Mapped to $_SERVER.
45
     * @var array $get    Mapped to $_GET.
46
     * @var array $post   Mapped to $_POST.
47
     * @var array $body   Mapped to request body, defaults to php://input.
48
     */
49
    private $server;
50
    private $get;
51
    private $post;
52
    private $body;
53
54
55
56
    /**
57
     * Constructor.
58
     */
59 44
    public function __construct()
60
    {
61 44
        $this->setGlobals();
62 44
    }
63
64
65
66
    /**
67
     * Read info from the globals.
68
     *
69
     * @param array $globals use to initiate globals with values.
70
     *
71
     * @return void
72
     */
73 44
    public function setGlobals($globals = [])
74
    {
75 44
        $this->server = [];
76 44
        $this->get = [];
77 44
        $this->post = [];
78
79 44
        $this->server = isset($globals["server"])
80 38
            ? array_merge($_SERVER, $globals["server"])
81 44
            : $_SERVER;
82
83 44
        $this->get = isset($globals["get"])
84 1
            ? array_merge($_GET, $globals["get"])
85 44
            : $_GET;
86
87 44
        $this->post = isset($globals["post"])
88 1
            ? array_merge($_POST, $globals["post"])
89 44
            : $_POST;
90 44
    }
91
92
93
94
    /**
95
     * Read info from the globals.
96
     *
97
     * @param array $globals use to initiate globals with values.
0 ignored issues
show
Bug introduced by
There is no parameter named $globals. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
98
     *
99
     * @return void
100
     */
101 4
    public function unsetGlobals()
102
    {
103 4
        $this->server = [];
104 4
        $this->get = [];
105 4
        $this->post = [];
106 4
    }
107
108
109
110
    /**
111
     * Init the request class by reading information from the request.
112
     *
113
     * @return $this
114
     */
115 14
    public function init()
116
    {
117 14
        $this->requestUri = rawurldecode($this->getServer("REQUEST_URI"));
118 14
        $scriptName = rawurldecode($this->getServer("SCRIPT_NAME"));
119 14
        $this->path = rtrim(dirname($scriptName), "/");
120 14
        $this->scriptName = basename($scriptName);
121
122
        // The route and its parts
123 14
        $this->extractRoute();
124
125
        // Prepare to create siteUrl and baseUrl by using currentUrl
126 14
        $this->currentUrl = $this->getCurrentUrl();
127 14
        $parts = parse_url($this->currentUrl);
128 14
        if ($parts === false) {
129 3
            $this->siteUrl = null;
130 3
            $this->baseUrl = null;
131 3
            return $this;
132
        }
133
134
        // Build the url from its parts
135 11
        $this->siteUrl = "{$parts["scheme"]}://{$parts["host"]}"
136 11
            . (isset($parts["port"])
137 2
                ? ":{$parts["port"]}"
138 11
                : "");
139 11
        $this->baseUrl = $this->siteUrl . $this->path;
140
141 11
        return $this;
142
    }
143
144
145
146
    /**
147
     * Get site url including scheme, host and port.
148
     *
149
     * @return string
150
     */
151 4
    public function getSiteUrl()
152
    {
153 4
        return $this->siteUrl;
154
    }
155
156
157
158
    /**
159
     * Get base url including site url and path to current index.php.
160
     *
161
     * @return string
162
     */
163 4
    public function getBaseUrl()
164
    {
165 4
        return $this->baseUrl;
166
    }
167
168
169
170
    /**
171
     * Get script name, index.php or other.
172
     *
173
     * @return string
174
     */
175 2
    public function getScriptName()
176
    {
177 2
        return $this->scriptName;
178
    }
179
180
181
182
    /**
183
     * Get route path parts in an array.
184
     *
185
     * @return array with route in its parts
186
     */
187 1
    public function getRouteParts()
188
    {
189 1
        return $this->routeParts;
190
    }
191
192
193
194
    /**
195
     * Get route path as a string.
196
     *
197
     * @return string as the current extracted route
198
     */
199 6
    public function getRoute()
200
    {
201 6
        return $this->route;
202
    }
203
204
205
206
    /**
207
     * Get the request method.
208
     *
209
     * @return string as the request method
210
     */
211 1
    public function getMethod()
212
    {
213 1
        return $this->getServer("REQUEST_METHOD");
214
    }
215
216
217
218
    /**
219
     * Extract the part containing the route.
220
     *
221
     * @todo Should be private, or useful in test?
222
     *
223
     * @return string as the current extracted route
224
     */
225 14
    public function extractRoute()
226
    {
227 14
        $requestUri = $this->requestUri;
228 14
        $scriptPath = $this->path;
229 14
        $scriptFile = $this->scriptName;
230
231
        // Compare REQUEST_URI and SCRIPT_NAME as long they match,
232
        // leave the rest as current request.
233 14
        $i = 0;
234 14
        $len = min(strlen($requestUri), strlen($scriptPath));
235 14
        while ($i < $len
236 14
               && $requestUri[$i] == $scriptPath[$i]
237
        ) {
238 10
            $i++;
239
        }
240 14
        $route = trim(substr($requestUri, $i), "/");
241
242
        // Does the request start with script-name - remove it.
243 14
        $len1 = strlen($route);
244 14
        $len2 = strlen($scriptFile);
245
246 14
        if ($len2 <= $len1
247 14
            && substr_compare($scriptFile, $route, 0, $len2, true) === 0
248
        ) {
249 10
            $route = substr($route, $len2 + 1);
250
        }
251
252
        // Remove the ?-part from the query when analysing controller/metod/arg1/arg2
253 14
        $queryPos = strpos($route, "?");
254 14
        if ($queryPos !== false) {
255 1
            $route = substr($route, 0, $queryPos);
256
        }
257
258 14
        $route = ($route === false) ? "" : $route;
259
260 14
        $this->route = $route;
261 14
        $this->routeParts = explode("/", trim($route, "/"));
262
263 14
        return $this->route;
264
    }
265
266
267
268
    /**
269
     * Get the current url.
270
     *
271
     * @param boolean $queryString attach query string, default is true.
272
     *
273
     * @return string as current url.
274
     */
275 29
    public function getCurrentUrl($queryString = true)
276
    {
277 29
        $port  = $this->getServer("SERVER_PORT");
278 29
        $https = $this->getServer("HTTPS") == "on" ? true : false;
279
280 29
        $scheme = $https
281 6
            ? "https"
282 29
            : $this->getServer("REQUEST_SCHEME", "http");
283
284 29
        $server = $this->getServer("SERVER_NAME")
285 29
            ?: $this->getServer("HTTP_HOST");
286
287 29
        $port  = ($port === "80")
288 16
            ? ""
289 13
            : (($port == 443 && $https)
290 3
                ? ""
291 29
                : ":" . $port);
292
293 29
        $uri = rawurldecode($this->getServer("REQUEST_URI"));
294 29
        $uri = $queryString
295 29
            ? rtrim($uri, "/")
296 29
            : rtrim(strtok($uri, "?"), "/");
297
298 29
        $url  = htmlspecialchars($scheme) . "://";
299 29
        $url .= htmlspecialchars($server)
300 29
            . $port . htmlspecialchars(rawurldecode($uri));
301
302 29
        return $url;
303
    }
304
305
306
307
    /**
308
     * Get a value from the _SERVER array and use default if it is not set.
309
     *
310
     * @param string $key     to check if it exists in the $_SERVER variable,
311
     *                        or empty to get whole array.
312
     * @param mixed  $default value to return as default
313
     *
314
     * @return mixed
315
     */
316 33
    public function getServer($key = null, $default = null)
317
    {
318 33
        if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
319 32
            return $this->server[$key] ?? $default;
320
        }
321
322 3
        return $this->server;
323
    }
324
325
326
327
    /**
328
     * Set variable in the server array.
329
     *
330
     * @param mixed  $key   the key an the , or an key-value array
331
     * @param string $value the value of the key
332
     *
333
     * @return self
334
     */
335 23 View Code Duplication
    public function setServer($key, $value = null) : object
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
    {
337 23
        if (is_array($key)) {
338 1
            $this->server = array_merge($this->server, $key);
339
        } else {
340 23
            $this->server[$key] = $value;
341
        }
342 23
        return $this;
343
    }
344
345
346
347
    /**
348
     * Check if the value from the _GET array exists.
349
     *
350
     * @param string $key     to check if it exists in the $_GET variable
351
     *
352
     * @return boolean
353
     */
354 1
    public function hasGet($key)
355
    {
356 1
        return array_key_exists($key, $this->get);
357
    }
358
359
360
361
    /**
362
     * Get a value from the _GET array and use default if it is not set.
363
     *
364
     * @param string $key     to check if it exists in the $_GET variable,
365
     *                        or empty to get whole array.
366
     * @param mixed  $default value to return as default
367
     *
368
     * @return mixed
369
     */
370 3 View Code Duplication
    public function getGet($key = null, $default = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372 3
        if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
373 2
            return $this->get[$key] ?? $default;
374
        }
375
376 3
        return $this->get;
377
    }
378
379
380
381
    /**
382
     * Set variable in the get array.
383
     *
384
     * @param mixed  $key   the key an the value, or an key-value array
385
     * @param string $value the value of the key
386
     *
387
     * @return self
388
     */
389 2 View Code Duplication
    public function setGet($key, $value = null) : object
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
390
    {
391 2
        if (is_array($key)) {
392 1
            $this->get = array_merge($this->get, $key);
393
        } else {
394 2
            $this->get[$key] = $value;
395
        }
396 2
        return $this;
397
    }
398
399
400
401
    /**
402
     * Get a value from the _POST array and use default if it is not set.
403
     *
404
     * @param string $key     to check if it exists in the $_POST variable,
405
     *                        or empty to get whole array.
406
     * @param mixed  $default value to return as default
407
     *
408
     * @return mixed
409
     */
410 3 View Code Duplication
    public function getPost($key = null, $default = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
411
    {
412 3
        if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
413 2
            return $this->post[$key] ?? $default;
414
        }
415
416 3
        return $this->post;
417
    }
418
419
420
421
    /**
422
     * Set variable in the post array.
423
     *
424
     * @param mixed  $key   the key an the value, or an key-value array
425
     * @param string $value the value of the key
426
     *
427
     * @return self
428
     */
429 2 View Code Duplication
    public function setPost($key, $value = null) : object
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
430
    {
431 2
        if (is_array($key)) {
432 1
            $this->post = array_merge($this->post, $key);
433
        } else {
434 2
            $this->post[$key] = $value;
435
        }
436 2
        return $this;
437
    }
438
439
440
441
    /**
442
     * Set the request body (useful for unit testing).
443
     *
444
     * @return self
445
     */
446 3
    public function setBody($body)
447
    {
448 3
        $this->body = $body;
449 3
    }
450
451
452
453
    /**
454
     * Get the request body.
455
     *
456
     * @return mixed
457
     */
458 3
    public function getBody()
459
    {
460 3
        return isset($this->body)
461 3
            ? $this->body
462 3
            : file_get_contents("php://input");
463
    }
464
465
466
467
    /**
468
     * Get the request body from the HTTP request and treat it as
469
     * JSON data, return null if request body is empty.
470
     *
471
     * @throws \JsonException when request body is invalid JSON.
472
     *
473
     * @return mixed as the JSON converted content or null if body is empty.
474
     */
475 2
    public function getBodyAsJson()
476
    {
477 2
        $body = $this->getBody();
478 2
        if ($body == "") {
479 1
            return null;
480
        }
481
482 2
        $entry = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
483
        return $entry;
484
    }
485
}
486