Completed
Push — master ( 7e948a...318388 )
by Mikael
02:50
created

Request::getBodyAsJson()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
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 string $server Mapped to $_SERVER.
45
     * @var string $get    Mapped to $_GET.
46
     * @var string $post   Mapped to $_POST.
47
     * @var string $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 27
    public function __construct()
60
    {
61 27
        $this->setGlobals();
62 27
    }
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 27
    public function setGlobals($globals = [])
74
    {
75 27
        $this->server = isset($globals["server"])
76 27
            ? array_merge($_SERVER, $globals["server"])
77 27
            : $_SERVER;
78
79 27
        $this->get = isset($globals["get"])
80
            ? array_merge($_GET, $globals["get"])
81 27
            : $_GET;
82
83 27
        $this->post = isset($globals["post"])
84
            ? array_merge($_POST, $globals["post"])
85 27
            : $_POST;
86 27
    }
87
88
89
90
    /**
91
     * Init the request class by reading information from the request.
92
     *
93
     * @return $this
94
     */
95 10
    public function init()
96
    {
97 10
        $this->requestUri = rawurldecode($this->getServer("REQUEST_URI"));
98 10
        $scriptName = rawurldecode($this->getServer("SCRIPT_NAME"));
99 10
        $this->path = rtrim(dirname($scriptName), "/");
100 10
        $this->scriptName = basename($scriptName);
101
102
        // The route and its parts
103 10
        $this->extractRoute();
104
105
        // Prepare to create siteUrl and baseUrl by using currentUrl
106 10
        $this->currentUrl = $this->getCurrentUrl();
107 10
        $parts = parse_url($this->currentUrl);
108 10
        $this->siteUrl = "{$parts["scheme"]}://{$parts["host"]}"
109 10
            . (isset($parts["port"])
110 2
                ? ":{$parts["port"]}"
111 10
                : "");
112 10
        $this->baseUrl = $this->siteUrl . $this->path;
113
114 10
        return $this;
115
    }
116
117
118
119
    /**
120
     * Get site url including scheme, host and port.
121
     *
122
     * @return string
123
     */
124 4
    public function getSiteUrl()
125
    {
126 4
        return $this->siteUrl;
127
    }
128
129
130
131
    /**
132
     * Get base url including site url and path to current index.php.
133
     *
134
     * @return string
135
     */
136 4
    public function getBaseUrl()
137
    {
138 4
        return $this->baseUrl;
139
    }
140
141
142
143
    /**
144
     * Get script name, index.php or other.
145
     *
146
     * @return string
147
     */
148
    public function getScriptName()
149
    {
150
        return $this->scriptName;
151
    }
152
153
154
155
    /**
156
     * Get route path parts in an array.
157
     *
158
     * @return array with route in its parts
159
     */
160
    public function getRouteParts()
161
    {
162
        return $this->routeParts;
163
    }
164
165
166
167
    /**
168
     * Get route path as a string.
169
     *
170
     * @return string as the current extracted route
171
     */
172 6
    public function getRoute()
173
    {
174 6
        return $this->route;
175
    }
176
177
178
179
    /**
180
     * Get the request method.
181
     *
182
     * @return string as the request method
183
     */
184 5
    public function getMethod()
185
    {
186 5
        return $this->getServer("REQUEST_METHOD");
187
    }
188
189
190
191
    /**
192
     * Extract the part containing the route.
193
     *
194
     * @todo Should be private, or useful in test?
195
     *
196
     * @return string as the current extracted route
197
     */
198 10
    public function extractRoute()
199
    {
200 10
        $requestUri = $this->requestUri;
201 10
        $scriptPath = $this->path;
202 10
        $scriptFile = $this->scriptName;
203
204
        // Compare REQUEST_URI and SCRIPT_NAME as long they match,
205
        // leave the rest as current request.
206 10
        $i = 0;
207 10
        $len = min(strlen($requestUri), strlen($scriptPath));
208 10
        while ($i < $len
209 10
               && $requestUri[$i] == $scriptPath[$i]
210
        ) {
211 10
            $i++;
212
        }
213 10
        $route = trim(substr($requestUri, $i), "/");
214
215
        // Does the request start with script-name - remove it.
216 10
        $len1 = strlen($route);
217 10
        $len2 = strlen($scriptFile);
218
219 10
        if ($len2 <= $len1
220 10
            && substr_compare($scriptFile, $route, 0, $len2, true) === 0
221
        ) {
222 10
            $route = substr($route, $len2 + 1);
223
        }
224
225
        // Remove the ?-part from the query when analysing controller/metod/arg1/arg2
226 10
        $queryPos = strpos($route, "?");
227 10
        if ($queryPos !== false) {
228
            $route = substr($route, 0, $queryPos);
229
        }
230
231 10
        $route = ($route === false) ? "" : $route;
232
233 10
        $this->route = $route;
234 10
        $this->routeParts = explode("/", trim($route, "/"));
235
236 10
        return $this->route;
237
    }
238
239
240
241
    /**
242
     * Get the current url.
243
     *
244
     * @param boolean $queryString attach query string, default is true.
245
     *
246
     * @return string as current url.
247
     */
248 25
    public function getCurrentUrl($queryString = true)
249
    {
250 25
        $port  = $this->getServer("SERVER_PORT");
251 25
        $https = $this->getServer("HTTPS") == "on" ? true : false;
252
253 25
        $scheme = $https
254 6
            ? "https"
255 25
            : $this->getServer("REQUEST_SCHEME", "http");
256
257 25
        $server = $this->getServer("SERVER_NAME")
258 25
            ?: $this->getServer("HTTP_HOST");
259
260 25
        $port  = ($port === "80")
261 15
            ? ""
262 10
            : (($port == 443 && $https)
263 3
                ? ""
264 25
                : ":" . $port);
265
266 25
        $uri = rawurldecode($this->getServer("REQUEST_URI"));
267 25
        $uri = $queryString
268 25
            ? rtrim($uri, "/")
269 25
            : rtrim(strtok($uri, "?"), "/");
270
271 25
        $url  = htmlspecialchars($scheme) . "://";
272 25
        $url .= htmlspecialchars($server)
273 25
            . $port . htmlspecialchars(rawurldecode($uri));
274
275 25
        return $url;
276
    }
277
278
279
280
    /**
281
     * Get a value from the _SERVER array and use default if it is not set.
282
     *
283
     * @param string $key     to check if it exists in the $_SERVER variable
284
     * @param string $default value to return as default
285
     *
286
     * @return mixed
287
     */
288 26
    public function getServer($key, $default = null)
289
    {
290 26
        return isset($this->server[$key]) ? $this->server[$key] : $default;
291
    }
292
293
294
295
    /**
296
     * Set variable in the server array.
297
     *
298
     * @param mixed  $key   the key an the , or an key-value array
299
     * @param string $value the value of the key
300
     *
301
     * @return self
302
     */
303 19 View Code Duplication
    public function setServer($key, $value = 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...
304
    {
305 19
        if (is_array($key)) {
306
            $this->server = array_merge($this->server, $key);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->server, $key) of type array is incompatible with the declared type string of property $server.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
307
        } else {
308 19
            $this->server[$key] = $value;
309
        }
310 19
        return $this;
311
    }
312
313
314
315
    /**
316
     * Check if the value from the _GET array exists.
317
     *
318
     * @param string $key     to check if it exists in the $_GET variable
319
     *
320
     * @return boolean
321
     */
322
    public function hasGet($key)
323
    {
324
        return array_key_exists($key, $this->get);
325
    }
326
327
328
329
    /**
330
     * Get a value from the _GET array and use default if it is not set.
331
     *
332
     * @param string $key     to check if it exists in the $_GET variable
333
     * @param string $default value to return as default
334
     *
335
     * @return mixed
336
     */
337 1
    public function getGet($key, $default = null)
338
    {
339 1
        return isset($this->get[$key]) ? $this->get[$key] : $default;
340
    }
341
342
343
344
    /**
345
     * Set variable in the get array.
346
     *
347
     * @param mixed  $key   the key an the , or an key-value array
348
     * @param string $value the value of the key
349
     *
350
     * @return self
351
     */
352 1 View Code Duplication
    public function setGet($key, $value = 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...
353
    {
354 1
        if (is_array($key)) {
355
            $this->get = array_merge($this->get, $key);
356
        } else {
357 1
            $this->get[$key] = $value;
358
        }
359 1
        return $this;
360
    }
361
362
363
364
    /**
365
     * Get a value from the _POST array and use default if it is not set.
366
     *
367
     * @param string $key     to check if it exists in the $_POST variable
368
     * @param string $default value to return as default
369
     *
370
     * @return mixed
371
     */
372
    public function getPost($key = null, $default = null)
373
    {
374
        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...
375
            return isset($this->post[$key]) ? $this->post[$key] : $default;
376
        }
377
378
        return $this->post;
379
    }
380
381
382
383
    /**
384
     * Set the request body (useful for unit testing).
385
     *
386
     * @return self
387
     */
388
    public function setBody($body)
389
    {
390
        $this->body = $body;
391
    }
392
393
394
395
    /**
396
     * Get the request body.
397
     *
398
     * @return mixed
399
     */
400
    public function getBody()
401
    {
402
        return isset($this->body)
403
            ? $this->body
404
            : file_get_contents("php://input");
405
    }
406
407
408
409
    /**
410
     * Get the request body from the HTTP request and treat it as
411
     * JSON data.
412
     *
413
     * @throws Anax\Request\Exception when request body is invalid JSON.
414
     *
415
     * @return mixed as the JSON converted content.
416
     */
417
    public function getBodyAsJson()
418
    {
419
        $entry = json_decode($this->getBody(), true);
420
        if (is_null($entry)) {
421
            throw new Exception("Could not read HTTP request body as JSON.");
422
        }
423
        return $entry;
424
    }
425
}
426