1 <?php namespace Modulework\Modules\Http;
2 3 4 5 6
7
8 use Modulework\Modules\Http\Utilities\FileCase;
9 use Modulework\Modules\Http\Utilities\ArrayCase;
10 use Modulework\Modules\Http\Utilities\HeaderCase;
11 use Modulework\Modules\Http\Utilities\ServerCase;
12
13 14 15 16 17 18
19 class Request
20 {
21
22 23 24 25
26 public $query;
27
28 29 30 31
32 public $request;
33
34 35 36 37
38 public $server;
39
40 41 42 43
44 public $files;
45
46 47 48 49
50 public $cookies;
51
52 53 54 55
56 public ;
57
58 59 60 61
62 protected $uri;
63
64 65 66 67
68 protected $path;
69
70 71 72 73
74 protected $baseUrl;
75
76 77 78 79
80 protected $basePath;
81
82 83 84 85
86 protected $method;
87
88 89 90 91
92 public static function makeFromGlobals()
93 {
94 return new static($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
95 }
96
97 98 99 100 101 102 103 104
105 public function __construct(array $query = array(), array $request = array(), array $cookies = array(), array $files = array(), array $server = array())
106 {
107 $this->init($query, $request, $cookies, $files, $server);
108 }
109
110 111 112 113 114
115 public function __toString()
116 {
117 return sprintf('%s %s >> %s', $this->server->get('SERVER_PROTOCOL'), $this->getMethod(), $this->getBaseUri());
118 }
119
120 121 122 123 124 125 126 127
128 public function init(array $query = array(), array $request = array(), array $cookies = array(), array $files = array(), array $server = array())
129 {
130 $this->query = new ArrayCase($query);
131 $this->request = new ArrayCase($request);
132 $this->cookies = new ArrayCase($cookies);
133 $this->files = new FileCase($files);
134 $this->server = new ServerCase($server);
135 $this->headers = new HeaderCase($this->server->getHeaders());
136
137
138 $this->uri = null;
139 $this->path = null;
140 $this->baseUrl = null;
141 $this->basePath = null;
142 $this->method = null;
143 }
144
145 146 147
148 public function applyChanges()
149 {
150 $_GET = $this->query->all();
151 $_POST = $this->request->all();
152 $_SERVER = $this->server->all();
153 $_COOKIE = $this->cookies->all();
154 }
155
156 157 158 159 160 161 162 163 164 165 166
167 public static function mock($uri, $method = 'GET', array $request = array(), array $cookies = array(), array $files = array(), array $server = array())
168 {
169 $server = array_replace(array(
170 'SERVER_PROTOCOL' => 'HTTP/1.1',
171 'SERVER_NAME' => 'localhost',
172 'SERVER_PORT' => 80,
173 'SCRIPT_NAME' => '',
174 'SCRIPT_FILENAME' => '',
175 'HTTP_HOST' => 'localhost',
176 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
177 'HTTP_USER_AGENT' => 'Modulework/Release',
178 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
179 'REQUEST_TIME' => time(),
180 ), $server);
181
182 $server['REQUEST_METHOD'] = strtoupper($method);
183
184
185 $parsed = parse_url($uri);
186
187 if (isset($parsed['host'])) {
188 $server['SERVER_NAME'] = $parsed['host'];
189 $server['HTTP_HOST'] = $parsed['host'];
190 }
191
192 if (isset($parsed['scheme'])) {
193 if ($parsed['scheme'] === 'https') {
194 $server['SERVER_PORT'] = 443;
195 $server['HTTPS'] = 'on';
196 } else {
197 $server['SERVER_PORT'] = 80;
198 unset($server['HTTPS']);
199 }
200 }
201
202 if (isset($parsed['port'])) {
203 $server['SERVER_PORT'] = $parsed['port'];
204 $server['HTTP_HOST'] .= ':' . $parsed['port'];
205 }
206
207
208
209 if (!isset($parsed['path'])) {
210 $parsed['path'] = '/';
211 }
212
213 $query = array();
214 if (isset($parsed['query'])) {
215 parse_str(html_entity_decode($parsed['query']), $query);
216 }
217
218 $queryString = http_build_query($query, '', '&');
219 $server['QUERY_STRING'] = $queryString;
220
221
222 $server['REQUEST_URI'] = $parsed['path'] . ('' == $queryString ? '' : '?' . $queryString);
223
224
225 return new static($query, $request, $cookies, $files, $server);
226 }
227
228 229 230 231 232
233 public static function normalizeQuery($query)
234 {
235 if ('' == $query) {
236 return '';
237 }
238
239 $parts = array();
240 $sort = array();
241
242 $split = explode('&', $query);
243
244 foreach ($split as $value) {
245 if ('' == $value || '=' === $value[0]) continue;
246
247 $pair = explode('=', $value, 2);
248
249 if (isset($pair[1])) {
250 $parts[] = rawurlencode(urldecode($pair[0])) . '=' . rawurlencode(urldecode($pair[1]));
251 } else {
252 $parts[] = rawurlencode(urldecode($pair[0]));
253 }
254
255 $sort[] = urldecode($pair[0]);
256 }
257
258 array_multisort($sort, SORT_ASC, $parts);
259
260 return implode('&', $parts);
261 }
262
263 264 265 266
267 public function getMethod()
268 {
269 if ($this->method === null) {
270 $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
271 }
272 return $this->method;
273 }
274
275 276 277 278
279 public function setMethod($method)
280 {
281 $this->$method = null;
282 $this->server->set('REQUEST_METHOD', strtoupper($method), true);
283 }
284
285 286 287 288 289
290 public function getScheme()
291 {
292 return $this->isSecure() ? 'https' : 'http';
293 }
294
295 296 297 298 299 300 301 302 303 304
305 public function getHttpHost()
306 {
307 $port = $this->getPort();
308 $scheme = $this->getScheme();
309
310 if (('https' == $scheme && $port == 443) || ('http' == $scheme && $port == 80)) {
311
312 return $this->getHost();
313 }
314
315 return $this->getHost() . ':' . $port;
316
317 }
318
319 320 321 322
323 public function getHost()
324 {
325 if (!$host = $this->headers->get('HOST')) {
326 if (!$host = $this->server->get('SERVER_ADDR')) {
327 $host = $this->server->get('SERVER_NAME', '');
328 }
329 }
330
331 $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
332
333 return $host;
334 }
335
336 337 338 339
340 public function setHost($host)
341 {
342 $this->headers->set('HOST', $host, true);
343 }
344
345 346 347 348
349 public function getPort()
350 {
351 return $this->server->get('SERVER_PORT');
352 }
353
354 355 356 357
358 public function getAcceptedEncodings()
359 {
360 return explode(',', $this->headers->get('ACCEPT_ENCODING'));
361 }
362
363 364 365 366 367
368 public function getBaseUri()
369 {
370 if ($this->uri === null) {
371 $this->uri = $this->generateBaseUri();
372 }
373 return $this->uri;
374 }
375
376 377 378 379
380 public function getBaseUrl()
381 {
382 if ($this->baseUrl === null) {
383 $this->baseUrl = $this->generateBaseUrl();
384 }
385 return $this->baseUrl;
386 }
387
388 389 390 391 392 393 394 395 396
397 public function getPath()
398 {
399 if ($this->path === null) {
400 $this->path = $this->generatePath();
401 }
402
403 return $this->path;
404 }
405
406 407 408 409 410 411 412
413 public function getBasePath()
414 {
415 if ($this->basePath === null) {
416 $this->basePath = $this->generateBasePath();
417 }
418
419 return $this->basePath;
420 }
421
422 423 424 425
426 public function root()
427 {
428 return rtrim($this->getScheme() . '://' . $this->getHost() . $this->getPath(), '/');
429 }
430
431 432 433 434
435 public function url()
436 {
437 return rtrim(preg_replace('/\?.*/', '', $this->getBaseUri()), '/');
438 }
439
440
441 442 443 444 445
446 public function segments()
447 {
448 $path = $this->getPath();
449
450 $array = $path == '/' ? array() : explode('/', $path);
451 return array_filter($array, function($val) {
452 return $val != '';
453 });
454 }
455
456 457 458 459 460 461 462
463 public function segment($index, $default = null)
464 {
465 if ('/' === $path = $this->getPath()) {
466 return '/';
467 }
468
469 $segments = explode('/', rtrim($path, '/'));
470
471
472 $segments = array_filter($segments, function($val) {
473 return $val != '';
474 });
475
476 return (isset($segments[$index])) ? $segments[$index] : $default;
477 }
478
479 480 481 482 483
484 public function isMethod($method)
485 {
486 return ($this->getMethod() === strtoupper($method));
487 }
488
489 490 491 492
493 public function isAjax()
494 {
495 return $this->isXmlHttpRequest();
496 }
497
498 499 500 501
502 public function isXmlHttpRequest()
503 {
504 return ('XMLHttpRequest' == $this->headers->get('X-Requested-With'));
505 }
506
507 508 509 510
511 public function isSecure()
512 {
513 return (1 == $this->server->get('HTTPS') || strtolower($this->server->get('HTTPS') == 'on'));
514 }
515
516 517 518 519
520 public function getClientIp()
521 {
522 return $this->server->get('REMOTE_ADDR');
523 }
524
525 526 527 528
529 public function getScript()
530 {
531 return $this->server->get('SCRIPT_NAME');
532 }
533
534
535 536 537 538
539 protected function generateBaseUri()
540 {
541 $uri = '';
542
543 544 545 546
547 if ($this->server->has('REQUEST_URI')) {
548 $uri = $this->server->get('REQUEST_URI');
549
550
551 $schemeHost = $this->getScheme() . '://' . $this->getHttpHost();
552 if (strpos($uri, $schemeHost) === 0) {
553 $uri = substr($uri, strlen($schemeHost));
554 }
555
556 } elseif ($this->server->has('ORIG_PATH_INFO')) {
557 $uri = $this->server->get('ORIG_PATH_INFO');
558 if ('' == $this->server->get('QUERY_STRING')) {
559 $uri .= '?' . $this->server->get('QUERY_STRING');
560 }
561
562 } elseif ($this->headers->has('X_ORIGINAL_URL')) {
563 $uri = $this->headers->get('X_ORIGINAL_URL');
564
565 } elseif ($this->headers->has('X_REWRITE_URL')) {
566 $this->headers->has('X_REWRITE_URL');
567
568 } elseif ($this->server->has('IIS_WasUrlRewritten') == '1' && ('' !== $this->server->get('UNENCODED_URL'))) {
569 $uri = $this->server->get('UNENCODED_URL');
570
571 } elseif ($this->server->has('IIS_WasUrlRewritten') == '1' && ('' !== $this->server->get('UNENCODED_URL'))) {
572 $uri = $this->server->get('UNENCODED_URL');
573
574 }
575
576 $this->server->set('REQUEST_URI', $uri);
577
578 return $uri;
579 }
580
581 582 583 584
585 protected function generateBaseUrl()
586 {
587 $filename = basename($this->server->get('SCRIPT_FILENAME'));
588
589 if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
590 $baseUrl = $this->server->get('SCRIPT_NAME');
591 } elseif (basename($this->server->get('PHP_SELF')) === $filename) {
592 $baseUrl = $this->server->get('PHP_SELF');
593 } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
594 $baseUrl = $this->server->get('ORIG_SCRIPT_NAME');
595 } else {
596 $path = $this->server->get('PHP_SELF', '');
597 $file = $this->server->get('SCRIPT_FILENAME', '');
598
599 $parts = array_reverse(explode('/', trim($file, '/')));
600
601 $i = 0;
602
603 $prev = count($parts);
604
605 $baseUrl = '';
606
607 do {
608 $part = $parts[$i];
609 $baseUrl = '/' . $part . $baseUrl;
610 $i++;
611 } while (($prev > $i) && (($pos = strpos($path, $baseUrl)) !== false) && (0 !== $pos));
612 }
613
614 $uri = $this->getBaseUri();
615
616 if ($baseUrl && false !== $pre = self::getPrefixUrlEncoded($uri, $baseUrl)) return $pre;
617
618 if ($baseUrl && false !== $pre = self::getPrefixUrlEncoded($uri, dirname($baseUrl))) return rtrim($prefix, '/');
619
620 if (($pos = strpos($uri, '?')) !== false) {
621 $queryLessUri = substr($uri, 0, $pos);
622 } else {
623 $queryLessUri = $uri;
624 }
625
626 $base = basename($baseUrl);
627
628 if (empty($base) || !strpos(rawurldecode($queryLessUri), $base)) return '';
629
630
631
632
633 return rtrim($baseUrl, '/');
634
635 }
636
637 protected function generateBasePath()
638 {
639 $filename = basename($this->server->get('SCRIPT_FILENAME'));
640 $baseUrl = $this->getBaseUrl();
641
642 if (empty($baseUrl)) return '';
643
644 $basePath = (basename($baseUrl) === $filename) ? dirname($baseUrl) : $baseUrl;
645
646 if ('\\' === DIRECTORY_SEPARATOR) {
647 $basePath = str_replace('\\', '/', $basePath);
648 }
649
650 return rtrim($basePath, '/');
651 }
652
653 protected function generatePath()
654 {
655 $baseUrl = $this->getBaseUrl();
656
657 if (($baseUri = $this->getBaseUri()) === null) return '/';
658
659 $path = '/';
660
661 if ($pos = strpos($baseUri, '?')) $baseUri = substr($baseUri, 0, $pos);
662
663 if ((null !== $baseUrl) && (false === ($path = substr($baseUri, strlen($baseUrl))))) {
664 return '/';
665 } elseif ($baseUrl === null) {
666 return $baseUri;
667 }
668
669 return $path;
670 }
671
672 673 674 675 676 677 678
679 protected static function getPrefixUrlEncoded($str, $pre)
680 {
681 if (strpos(rawurldecode($str), $pre) !== 0) return false;
682
683 $length = strlen($pre);
684
685 686 687
688 if (preg_match("#^(%[[:xdigit:]]{2}|.){{$length}}#", $str, $match)) return $match[0];
689
690 return false;
691 }
692
693
694
695 }