Completed
Push — master ( fb73f4...7073ad )
by Mikael
02:44
created

Request::unsetGlobals()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
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 30
    public function __construct()
60
    {
61 30
        $this->setGlobals();
62 30
    }
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 30
    public function setGlobals($globals = [])
74
    {
75 30
        $this->server = [];
76 30
        $this->get = [];
77 30
        $this->post = [];
78
79 30
        $this->server = isset($globals["server"])
80 27
            ? array_merge($_SERVER, $globals["server"])
81 30
            : $_SERVER;
82
83 30
        $this->get = isset($globals["get"])
84 1
            ? array_merge($_GET, $globals["get"])
85 30
            : $_GET;
86
87 30
        $this->post = isset($globals["post"])
88 1
            ? array_merge($_POST, $globals["post"])
89 30
            : $_POST;
90 30
    }
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 10
    public function init()
116
    {
117 10
        $this->requestUri = rawurldecode($this->getServer("REQUEST_URI"));
118 10
        $scriptName = rawurldecode($this->getServer("SCRIPT_NAME"));
119 10
        $this->path = rtrim(dirname($scriptName), "/");
120 10
        $this->scriptName = basename($scriptName);
121
122
        // The route and its parts
123 10
        $this->extractRoute();
124
125
        // Prepare to create siteUrl and baseUrl by using currentUrl
126 10
        $this->currentUrl = $this->getCurrentUrl();
127 10
        $parts = parse_url($this->currentUrl);
128 10
        $this->siteUrl = "{$parts["scheme"]}://{$parts["host"]}"
129 10
            . (isset($parts["port"])
130 2
                ? ":{$parts["port"]}"
131 10
                : "");
132 10
        $this->baseUrl = $this->siteUrl . $this->path;
133
134 10
        return $this;
135
    }
136
137
138
139
    /**
140
     * Get site url including scheme, host and port.
141
     *
142
     * @return string
143
     */
144 4
    public function getSiteUrl()
145
    {
146 4
        return $this->siteUrl;
147
    }
148
149
150
151
    /**
152
     * Get base url including site url and path to current index.php.
153
     *
154
     * @return string
155
     */
156 4
    public function getBaseUrl()
157
    {
158 4
        return $this->baseUrl;
159
    }
160
161
162
163
    /**
164
     * Get script name, index.php or other.
165
     *
166
     * @return string
167
     */
168
    public function getScriptName()
169
    {
170
        return $this->scriptName;
171
    }
172
173
174
175
    /**
176
     * Get route path parts in an array.
177
     *
178
     * @return array with route in its parts
179
     */
180
    public function getRouteParts()
181
    {
182
        return $this->routeParts;
183
    }
184
185
186
187
    /**
188
     * Get route path as a string.
189
     *
190
     * @return string as the current extracted route
191
     */
192 6
    public function getRoute()
193
    {
194 6
        return $this->route;
195
    }
196
197
198
199
    /**
200
     * Get the request method.
201
     *
202
     * @return string as the request method
203
     */
204 1
    public function getMethod()
205
    {
206 1
        return $this->getServer("REQUEST_METHOD");
207
    }
208
209
210
211
    /**
212
     * Extract the part containing the route.
213
     *
214
     * @todo Should be private, or useful in test?
215
     *
216
     * @return string as the current extracted route
217
     */
218 10
    public function extractRoute()
219
    {
220 10
        $requestUri = $this->requestUri;
221 10
        $scriptPath = $this->path;
222 10
        $scriptFile = $this->scriptName;
223
224
        // Compare REQUEST_URI and SCRIPT_NAME as long they match,
225
        // leave the rest as current request.
226 10
        $i = 0;
227 10
        $len = min(strlen($requestUri), strlen($scriptPath));
228 10
        while ($i < $len
229 10
               && $requestUri[$i] == $scriptPath[$i]
230
        ) {
231 10
            $i++;
232
        }
233 10
        $route = trim(substr($requestUri, $i), "/");
234
235
        // Does the request start with script-name - remove it.
236 10
        $len1 = strlen($route);
237 10
        $len2 = strlen($scriptFile);
238
239 10
        if ($len2 <= $len1
240 10
            && substr_compare($scriptFile, $route, 0, $len2, true) === 0
241
        ) {
242 10
            $route = substr($route, $len2 + 1);
243
        }
244
245
        // Remove the ?-part from the query when analysing controller/metod/arg1/arg2
246 10
        $queryPos = strpos($route, "?");
247 10
        if ($queryPos !== false) {
248
            $route = substr($route, 0, $queryPos);
249
        }
250
251 10
        $route = ($route === false) ? "" : $route;
252
253 10
        $this->route = $route;
254 10
        $this->routeParts = explode("/", trim($route, "/"));
255
256 10
        return $this->route;
257
    }
258
259
260
261
    /**
262
     * Get the current url.
263
     *
264
     * @param boolean $queryString attach query string, default is true.
265
     *
266
     * @return string as current url.
267
     */
268 25
    public function getCurrentUrl($queryString = true)
269
    {
270 25
        $port  = $this->getServer("SERVER_PORT");
271 25
        $https = $this->getServer("HTTPS") == "on" ? true : false;
272
273 25
        $scheme = $https
274 6
            ? "https"
275 25
            : $this->getServer("REQUEST_SCHEME", "http");
276
277 25
        $server = $this->getServer("SERVER_NAME")
278 25
            ?: $this->getServer("HTTP_HOST");
279
280 25
        $port  = ($port === "80")
281 15
            ? ""
282 10
            : (($port == 443 && $https)
283 3
                ? ""
284 25
                : ":" . $port);
285
286 25
        $uri = rawurldecode($this->getServer("REQUEST_URI"));
287 25
        $uri = $queryString
288 25
            ? rtrim($uri, "/")
289 25
            : rtrim(strtok($uri, "?"), "/");
290
291 25
        $url  = htmlspecialchars($scheme) . "://";
292 25
        $url .= htmlspecialchars($server)
293 25
            . $port . htmlspecialchars(rawurldecode($uri));
294
295 25
        return $url;
296
    }
297
298
299
300
    /**
301
     * Get a value from the _SERVER array and use default if it is not set.
302
     *
303
     * @param string $key     to check if it exists in the $_SERVER variable,
304
     *                        or empty to get whole array.
305
     * @param mixed  $default value to return as default
306
     *
307
     * @return mixed
308
     */
309 28
    public function getServer($key = null, $default = null)
310
    {
311 28
        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...
312 27
            return $this->server[$key] ?? $default;
313
        }
314
315 2
        return $this->server;
316
    }
317
318
319
320
    /**
321
     * Set variable in the server array.
322
     *
323
     * @param mixed  $key   the key an the , or an key-value array
324
     * @param string $value the value of the key
325
     *
326
     * @return self
327
     */
328 20 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...
329
    {
330 20
        if (is_array($key)) {
331 1
            $this->server = array_merge($this->server, $key);
332
        } else {
333 20
            $this->server[$key] = $value;
334
        }
335 20
        return $this;
336
    }
337
338
339
340
    /**
341
     * Check if the value from the _GET array exists.
342
     *
343
     * @param string $key     to check if it exists in the $_GET variable
344
     *
345
     * @return boolean
346
     */
347 1
    public function hasGet($key)
348
    {
349 1
        return array_key_exists($key, $this->get);
350
    }
351
352
353
354
    /**
355
     * Get a value from the _GET array and use default if it is not set.
356
     *
357
     * @param string $key     to check if it exists in the $_GET variable,
358
     *                        or empty to get whole array.
359
     * @param mixed  $default value to return as default
360
     *
361
     * @return mixed
362
     */
363 2 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...
364
    {
365 2
        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...
366 1
            return $this->get[$key] ?? $default;
367
        }
368
369 2
        return $this->get;
370
    }
371
372
373
374
    /**
375
     * Set variable in the get array.
376
     *
377
     * @param mixed  $key   the key an the value, or an key-value array
378
     * @param string $value the value of the key
379
     *
380
     * @return self
381
     */
382 1 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...
383
    {
384 1
        if (is_array($key)) {
385 1
            $this->get = array_merge($this->get, $key);
386
        } else {
387 1
            $this->get[$key] = $value;
388
        }
389 1
        return $this;
390
    }
391
392
393
394
    /**
395
     * Get a value from the _POST array and use default if it is not set.
396
     *
397
     * @param string $key     to check if it exists in the $_POST variable,
398
     *                        or empty to get whole array.
399
     * @param mixed  $default value to return as default
400
     *
401
     * @return mixed
402
     */
403 2 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...
404
    {
405 2
        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...
406 1
            return $this->post[$key] ?? $default;
407
        }
408
409 2
        return $this->post;
410
    }
411
412
413
414
    /**
415
     * Set variable in the post array.
416
     *
417
     * @param mixed  $key   the key an the value, or an key-value array
418
     * @param string $value the value of the key
419
     *
420
     * @return self
421
     */
422 1 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...
423
    {
424 1
        if (is_array($key)) {
425 1
            $this->post = array_merge($this->post, $key);
426
        } else {
427 1
            $this->post[$key] = $value;
428
        }
429 1
        return $this;
430
    }
431
432
433
434
    /**
435
     * Set the request body (useful for unit testing).
436
     *
437
     * @return self
438
     */
439
    public function setBody($body)
440
    {
441
        $this->body = $body;
442
    }
443
444
445
446
    /**
447
     * Get the request body.
448
     *
449
     * @return mixed
450
     */
451
    public function getBody()
452
    {
453
        return isset($this->body)
454
            ? $this->body
455
            : file_get_contents("php://input");
456
    }
457
458
459
460
    /**
461
     * Get the request body from the HTTP request and treat it as
462
     * JSON data.
463
     *
464
     * @throws Anax\Request\Exception when request body is invalid JSON.
465
     *
466
     * @return mixed as the JSON converted content.
467
     */
468
    public function getBodyAsJson()
469
    {
470
        $entry = json_decode($this->getBody(), true);
471
        if (is_null($entry)) {
472
            throw new Exception("Could not read HTTP request body as JSON.");
473
        }
474
        return $entry;
475
    }
476
}
477