Completed
Push — master ( 59aba1...b92142 )
by Mikael
04:59
created

Request::extractRoute()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 40
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7.0046

Importance

Changes 0
Metric Value
dl 0
loc 40
ccs 21
cts 22
cp 0.9545
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 22
nc 16
nop 0
crap 7.0046
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
     * Get a value from the _GET array and use default if it is not set.
317
     *
318
     * @param string $key     to check if it exists in the $_GET variable
319
     * @param string $default value to return as default
320
     *
321
     * @return mixed
322
     */
323 1
    public function getGet($key, $default = null)
324
    {
325 1
        return isset($this->get[$key]) ? $this->get[$key] : $default;
326
    }
327
328
329
330
    /**
331
     * Set variable in the get array.
332
     *
333
     * @param mixed  $key   the key an the , or an key-value array
334
     * @param string $value the value of the key
335
     *
336
     * @return self
337
     */
338 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...
339
    {
340 1
        if (is_array($key)) {
341
            $this->get = array_merge($this->get, $key);
342
        } else {
343 1
            $this->get[$key] = $value;
344
        }
345 1
        return $this;
346
    }
347
348
349
350
    /**
351
     * Get a value from the _POST array and use default if it is not set.
352
     *
353
     * @param string $key     to check if it exists in the $_POST variable
354
     * @param string $default value to return as default
355
     *
356
     * @return mixed
357
     */
358
    public function getPost($key = null, $default = null)
359
    {
360
        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...
361
            return isset($this->post[$key]) ? $this->post[$key] : $default;
362
        }
363
364
        return $this->post;
365
    }
366
367
368
369
    /**
370
     * Set the request body (useful for unit testing).
371
     *
372
     * @return self
373
     */
374
    public function setBody($body)
375
    {
376
        $this->body = $body;
377
    }
378
379
380
381
    /**
382
     * Get the request body.
383
     *
384
     * @return mixed
385
     */
386
    public function getBody()
387
    {
388
        return isset($this->body)
389
            ? $this->body
390
            : file_get_contents("php://input");
391
    }
392
}
393