-
Notifications
You must be signed in to change notification settings - Fork 1
/
Request.php
403 lines (368 loc) · 12.6 KB
/
Request.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
<?php
namespace TgUtils;
use TgLog\Log;
use TgLog\Error;
/** Holds information about an HTTP request */
class Request {
public const DEFAULT_REQUEST_URI = 'https://www.example.com/';
/** the default instance from globals */
protected static $request;
/**
* Returns the singleton request.
* @return Request the request object
*/
public static function getRequest() {
if (!self::$request) {
self::$request = new Request();
}
return self::$request;
}
/** The protocol (http or https) */
public $protocol;
/** The HTTP method */
public $method;
/** All headers from the request as array */
public $headers;
/** The host as the user requested it (can differ from $httpHost in reverse proxy setups) */
public $host;
/** The URI to the root of the server, combination of protocol and host. */
public $rootUri;
/** The HTTP host - the host mentioned in Host: header */
public $httpHost;
/** The URI which includes the parameters */
public $uri;
/** The path of the request. Does not include parameters */
public $path;
/** The path of the original request (requested at proxy). Does not include parameters */
public $originalPath;
/** The original request (requested at proxy). Includes parameters */
public $originalUri;
/** The path split in its elements */
public $pathElements;
/** The parameters as a string */
public $params;
/** The path parameters (GET params) */
public $getParams;
/** The (context) document root */
public $documentRoot;
/** The web root as seen by the user, usually '/' or an alias or mapped path from a proxy */
public $webRoot;
/** The web root as defined by the local web server */
public $localWebRoot;
/** The web root URI as it can be requested by the user */
public $webRootUri;
/** The epoch time in seconds when the request was created */
public $startTime;
/** Usually the document root */
public $appRoot;
/** relative path from docroot to the app root, usually empty */
public $relativeAppPath;
/** The body of the request (intentionally not public) */
protected $body;
/** The post params of the request */
protected $postParams;
/** DEPRECATED: The language code for this request (by default: en) */
public $langCode;
/** Constructor */
public function __construct() {
// Sequence matters!
$this->method = $_SERVER['REQUEST_METHOD'];
$this->headers = $this->initHeaders();
$this->protocol = $this->initProtocol();
$this->httpHost = $_SERVER['HTTP_HOST'];
$this->host = $this->initHost();
$this->rootUri = $this->initRootUri();
if (isset($_SERVER['REQUEST_URI'])) {
$this->uri = $_SERVER['REQUEST_URI'];
} else {
$this->uri = Request::DEFAULT_REQUEST_URI;
}
$uri_parts = explode('?', $this->uri, 2);
$this->path = $uri_parts[0];
$this->pathElements = $this->initPathElements();
$this->params = count($uri_parts) > 1 ? $uri_parts[1] : '';
$this->getParams = $this->initGetParams();
$this->postParams = NULL;
$this->body = NULL;
$this->documentRoot = $this->initDocumentRoot();
$this->webRoot = $this->initWebRoot(TRUE);
$this->originalPath = $this->initOriginalPath();
$this->originalUri = $this->initOriginalUri();
$this->localWebRoot = $this->initWebRoot(FALSE);
$this->webRootUri = $this->initWebRootUri();
$this->appRoot = $this->documentRoot;
$this->relativeAppPath = '';
$this->startTime = time();
// Will be deprecated
$this->langCode = 'en';
}
/**
* Different products return different keys in headers. We make all keys lowercase here.
*/
protected function initHeaders() {
$headers = getallheaders();
$rc = array();
foreach ($headers AS $key => $value) {
$rc[strtolower($key)] = $value;
}
return $rc;
}
/**
* Returns the server hostname that was requested.
* <p>The host is extracted from HTTP_X_FORWARDED_HOST or when not set
* taken by the function getHttpHost(). Forwarded hosts return multiple
* hosts eventually (e.g. when using reverse proxies). The last such
* host is returned then.</p>
* @return string the Host requested by the user.
*/
protected function initHost() {
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$forwarded = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
$last = trim($forwarded[count($forwarded)-1]);
$first = trim($forwarded[0]);
if ($first != $this->httpHost) return $first;
if ($last != $this->httpHost) return $last;
}
return $this->httpHost;
}
/**
* Returns the protocol (http, https) being used by the user.
* <p>The protocol can be switched at reverse proxies, that's
* why the HTTP_X_FORWARDED_PROTO variable is checked.
* Otherwise it will be the REQUEST_SCHEME.</p>
* @return string the protocol as used by the user.
*/
protected function initProtocol() {
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
return $_SERVER['HTTP_X_FORWARDED_PROTO'];
}
return $_SERVER['REQUEST_SCHEME'];
}
/**
* Returns the base for the URI - protocol and host.
*/
protected function initRootUri() {
return $this->protocol.'://'.$this->host;
}
/**
* Returns all path elements with .html stripped of if detected.
* <p>E.g. /my/path/index.html will return three elements: my, path and index.</p>
* @return array the path elements.
*/
protected function initPathElements() {
$path = substr($this->path, 1);
if (substr($path, strlen($path)-5) == '.html') $path = substr($path, 0, strlen($path)-5);
if (substr($path, strlen($path)-1) == '/') $path = substr($path, 0, strlen($path)-1);
$elems = explode('/', $path);
if ((count($elems) == 1) && ($elems[0] == '')) $elems = array();
return $elems;
}
/**
* Returns whether a specific key was given as parameter.
* @return TRUE when parameter was set.
*/
public function hasGetParam($key) {
$params = $this->getParams;
return isset($params[$key]);
}
/**
* Returns the GET parameter value from the request.
* @param string $key - the parameter name
* @param mixed $default - the default value to return when parameter does not exist (optional, default is NULL).
* @param object $filter - a filter to sanitize the value.
* @return mixed the parameter value or its default.
*/
public function getGetParam($key, $default = NULL, $filter = NULL) {
$params = $this->getParams;
if ($filter == NULL) $filter = NoHtmlStringFilter::$INSTANCE;
return isset($params[$key]) ? $filter->filter($params[$key]) : $default;
}
/**
* Returns the parameters as an array.
* @return array array of parameters.
*/
protected function initGetParams() {
return self::parseQueryString($this->params);
}
/**
* Returns whether a specific key was given as parameter in POST request.
* @return TRUE when parameter was set.
*/
public function hasPostParam($key) {
$params = $this->getPostParams();
return isset($params[$key]);
}
/**
* Returns the POST parameter value from the request.
* @param string $key - the parameter name
* @param mixed $default - the default value to return when parameter does not exist (optional, default is NULL).
* @param object $filter - a filter to sanitize the value.
* @return mixed the parameter value or its default.
*/
public function getPostParam($key, $default = NULL, $filter = NULL) {
$params = $this->getPostParams();
if ($filter == NULL) $filter = NoHtmlStringFilter::$INSTANCE;
return isset($params[$key]) ? $filter->filter($params[$key]) : $default;
}
/**
* Returns an array of all POST parameters.
* @return array post parameters
*/
public function getPostParams() {
if ($this->postParams == NULL) {
$this->postParams = array();
// Check that we have content-length
$len = $this->getHeader('Content-Length');
if ($len) {
$len = intval($len);
// Check that we have a valid content-length
if ($len>0) {
$this->postParams = $_POST;
} else {
Log::register(new Error('POST content invalid'));
}
}
}
return $this->postParams;
}
/**
* Returns the body of the request (POST and PUT requests only).
* @return string the request body.
*/
public function getBody() {
if (in_array($this->method, array('POST', 'PUT'))) {
if ($this->body == NULL) {
$this->body = file_get_contents('php://input');
}
}
return $this->body;
}
/**
* Parses the query string.
* @param $s - the query parameter string
* @return array the query parameter values.
*/
public static function parseQueryString($s) {
$rc = array();
parse_str($s, $rc);
return $rc;
}
/**
* Returns a header value.
* @param string $key - the header key
* @return string the value of the header.
*/
public function getHeader($key) {
if (isset($this->headers[strtolower($key)])) return $this->headers[strtolower($key)];
return NULL;
}
/**
* Returns a GET or POST parameter when given.
* <p>The method will search GET and POST parameters for the given key and return the
* first it finds.</p>
* @param string $key - the parameter name.
* @param mixed $default - the default value when not found (optional, default is NULL)
* @param boolean $getPrecedes - TRUE when GET parameter shall be returned even when POST parameter is given. (optional, default is TRUE).
* @return string the parameter value or its default.
*/
public function getParam($key, $default = NULL, $getPrecedes = true) {
$rc = $getPrecedes ? $this->getGetParam($key) : $this->getPostParam($key);
if ($rc == NULL) $rc = $getPrecedes ? $this->getPostParam($key) : $this->getGetParam($key);
if ($rc == NULL) $rc = $default;
return $rc;
}
/**
* Returns the time since the request started.
* @return int elapsed time in seconds.
*/
public function getElapsedTime() {
return time() - $this->startTime;
}
/**
* Returns the document root - this is the real path name of the web root.
* @return string the document root or context document root if available.
*/
protected function initDocumentRoot() {
if (isset($_SERVER['CONTEXT_DOCUMENT_ROOT'])) {
return $_SERVER['CONTEXT_DOCUMENT_ROOT'];
}
return $_SERVER['DOCUMENT_ROOT'];
}
/**
* Returns the original path as request by the end user.
* The path might be different from $this->path as
* a webroot mapping might be involved.
*/
protected function initOriginalPath() {
$rc = $this->path;
$rootDef = isset($_SERVER['HTTP_X_FORWARDED_ROOT']) ? $_SERVER['HTTP_X_FORWARDED_ROOT'] : '';
if ($rootDef) {
$arr = explode(',', $rootDef);
if (strpos($rc, $arr[0]) === 0) {
$rc = $arr[1].substr($rc, strlen($arr[0]));
}
}
return $rc;
}
/**
* Returns the original URI as request by the end user.
* The path might be different from $this->path as
* a webroot mapping might be involved.
*/
protected function initOriginalUri() {
$rc = $this->originalPath;
if ($this->params) {
$rc .= '?'.$this->params;
}
return $rc;
}
/**
* Returns the web root - that is the web path where the current
* script is rooted and usually the base path for an application.
* <p>$_SERVER['PHP_SELF'] or $_SERVER['SCRIPT_NAME']</p> will
* be misleading as they would not tell the real document root.</p>
* @return string the presumed web root.
*/
protected function initWebRoot($considerForwarding = TRUE) {
if ($considerForwarding) {
$rootDef = isset($_SERVER['HTTP_X_FORWARDED_ROOT']) ? $_SERVER['HTTP_X_FORWARDED_ROOT'] : '';
if ($rootDef) {
$arr = explode(',', $rootDef);
$rc = $arr[1];
if ((strlen($rc) > 0) && (substr($rc, -1) == '/')) $rc = substr($rc, 0, strlen($rc)-1);
return $rc;
}
}
$docRoot = $this->documentRoot;
$fileDir = dirname($_SERVER['SCRIPT_FILENAME']);
$webRoot = substr($fileDir, strlen($docRoot));
if (isset($_SERVER['CONTEXT'])) {
$webRoot = $_SERVER['CONTEXT'].$webRoot;
}
if ((strlen($webRoot) > 0) && (substr($webRoot, -1) == '/')) $webRoot = substr($rc, 0, strlen($webRoot)-1);
return $webRoot;
}
/**
* Returns the full URL of the web root.
* @return string the URL to the root dir.
*/
protected function initWebRootUri() {
$protocol = $this->protocol;
$host = $this->host;
return $protocol.'://'.$host.$this->webRoot;
}
/**
* Initializes the appRoot and relativeAppPath according to the root of the app.
* The appRoot can differ from document root as it can be installed in a subdir.
* @param string $appRoot - the application root directory (absolute path)
*/
public function setAppRoot($appRoot) {
$appRootLen = strlen($appRoot);
$docRootLen = strlen($this->documentRoot);
if (($docRootLen < $appRootLen) && (strpos($appRoot, $this->documentRoot) === 0)) {
$this->relativeAppPath = substr($appRoot, $docRootLen);
} else {
$this->relativeAppPath = '';
}
}
}