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) |
|
|
|
|
304
|
|
|
{ |
305
|
19 |
|
if (is_array($key)) { |
306
|
|
|
$this->server = array_merge($this->server, $key); |
|
|
|
|
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) |
|
|
|
|
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) { |
|
|
|
|
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
|
|
|
|
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.