1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\HttpFoundation;
13:
14: use Symfony\Component\HttpFoundation\Session\SessionInterface;
15:
16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
31: class Request
32: {
33: const HEADER_CLIENT_IP = 'client_ip';
34: const HEADER_CLIENT_HOST = 'client_host';
35: const HEADER_CLIENT_PROTO = 'client_proto';
36: const HEADER_CLIENT_PORT = 'client_port';
37:
38: const METHOD_HEAD = 'HEAD';
39: const METHOD_GET = 'GET';
40: const METHOD_POST = 'POST';
41: const METHOD_PUT = 'PUT';
42: const METHOD_PATCH = 'PATCH';
43: const METHOD_DELETE = 'DELETE';
44: const METHOD_PURGE = 'PURGE';
45: const METHOD_OPTIONS = 'OPTIONS';
46: const METHOD_TRACE = 'TRACE';
47: const METHOD_CONNECT = 'CONNECT';
48:
49: protected static $trustedProxies = array();
50:
51: 52: 53:
54: protected static $trustedHostPatterns = array();
55:
56: 57: 58:
59: protected static $trustedHosts = array();
60:
61: 62: 63: 64: 65: 66: 67:
68: protected static $trustedHeaders = array(
69: self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
70: self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
71: self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
72: self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
73: );
74:
75: protected static $httpMethodParameterOverride = false;
76:
77: 78: 79: 80: 81: 82: 83:
84: public $attributes;
85:
86: 87: 88: 89: 90: 91: 92:
93: public $request;
94:
95: 96: 97: 98: 99: 100: 101:
102: public $query;
103:
104: 105: 106: 107: 108: 109: 110:
111: public $server;
112:
113: 114: 115: 116: 117: 118: 119:
120: public $files;
121:
122: 123: 124: 125: 126: 127: 128:
129: public $cookies;
130:
131: 132: 133: 134: 135: 136: 137:
138: public $headers;
139:
140: 141: 142:
143: protected $content;
144:
145: 146: 147:
148: protected $languages;
149:
150: 151: 152:
153: protected $charsets;
154:
155: 156: 157:
158: protected $encodings;
159:
160: 161: 162:
163: protected $acceptableContentTypes;
164:
165: 166: 167:
168: protected $pathInfo;
169:
170: 171: 172:
173: protected $requestUri;
174:
175: 176: 177:
178: protected $baseUrl;
179:
180: 181: 182:
183: protected $basePath;
184:
185: 186: 187:
188: protected $method;
189:
190: 191: 192:
193: protected $format;
194:
195: 196: 197:
198: protected $session;
199:
200: 201: 202:
203: protected $locale;
204:
205: 206: 207:
208: protected $defaultLocale = 'en';
209:
210: 211: 212:
213: protected static $formats;
214:
215: protected static $requestFactory;
216:
217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229:
230: public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
231: {
232: $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
233: }
234:
235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249:
250: public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
251: {
252: $this->request = new ParameterBag($request);
253: $this->query = new ParameterBag($query);
254: $this->attributes = new ParameterBag($attributes);
255: $this->cookies = new ParameterBag($cookies);
256: $this->files = new FileBag($files);
257: $this->server = new ServerBag($server);
258: $this->headers = new HeaderBag($this->server->getHeaders());
259:
260: $this->content = $content;
261: $this->languages = null;
262: $this->charsets = null;
263: $this->encodings = null;
264: $this->acceptableContentTypes = null;
265: $this->pathInfo = null;
266: $this->requestUri = null;
267: $this->baseUrl = null;
268: $this->basePath = null;
269: $this->method = null;
270: $this->format = null;
271: }
272:
273: 274: 275: 276: 277: 278: 279:
280: public static function createFromGlobals()
281: {
282:
283:
284:
285: $server = $_SERVER;
286: if ('cli-server' === php_sapi_name()) {
287: if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
288: $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
289: }
290: if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
291: $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
292: }
293: }
294:
295: $request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server);
296:
297: if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
298: && in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
299: ) {
300: parse_str($request->getContent(), $data);
301: $request->request = new ParameterBag($data);
302: }
303:
304: return $request;
305: }
306:
307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324:
325: public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
326: {
327: $server = array_replace(array(
328: 'SERVER_NAME' => 'localhost',
329: 'SERVER_PORT' => 80,
330: 'HTTP_HOST' => 'localhost',
331: 'HTTP_USER_AGENT' => 'Symfony/2.X',
332: 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
333: 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
334: 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
335: 'REMOTE_ADDR' => '127.0.0.1',
336: 'SCRIPT_NAME' => '',
337: 'SCRIPT_FILENAME' => '',
338: 'SERVER_PROTOCOL' => 'HTTP/1.1',
339: 'REQUEST_TIME' => time(),
340: ), $server);
341:
342: $server['PATH_INFO'] = '';
343: $server['REQUEST_METHOD'] = strtoupper($method);
344:
345: $components = parse_url($uri);
346: if (isset($components['host'])) {
347: $server['SERVER_NAME'] = $components['host'];
348: $server['HTTP_HOST'] = $components['host'];
349: }
350:
351: if (isset($components['scheme'])) {
352: if ('https' === $components['scheme']) {
353: $server['HTTPS'] = 'on';
354: $server['SERVER_PORT'] = 443;
355: } else {
356: unset($server['HTTPS']);
357: $server['SERVER_PORT'] = 80;
358: }
359: }
360:
361: if (isset($components['port'])) {
362: $server['SERVER_PORT'] = $components['port'];
363: $server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$components['port'];
364: }
365:
366: if (isset($components['user'])) {
367: $server['PHP_AUTH_USER'] = $components['user'];
368: }
369:
370: if (isset($components['pass'])) {
371: $server['PHP_AUTH_PW'] = $components['pass'];
372: }
373:
374: if (!isset($components['path'])) {
375: $components['path'] = '/';
376: }
377:
378: switch (strtoupper($method)) {
379: case 'POST':
380: case 'PUT':
381: case 'DELETE':
382: if (!isset($server['CONTENT_TYPE'])) {
383: $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
384: }
385:
386: case 'PATCH':
387: $request = $parameters;
388: $query = array();
389: break;
390: default:
391: $request = array();
392: $query = $parameters;
393: break;
394: }
395:
396: $queryString = '';
397: if (isset($components['query'])) {
398: parse_str(html_entity_decode($components['query']), $qs);
399:
400: if ($query) {
401: $query = array_replace($qs, $query);
402: $queryString = http_build_query($query, '', '&');
403: } else {
404: $query = $qs;
405: $queryString = $components['query'];
406: }
407: } elseif ($query) {
408: $queryString = http_build_query($query, '', '&');
409: }
410:
411: $server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
412: $server['QUERY_STRING'] = $queryString;
413:
414: return self::createRequestFromFactory($query, $request, array(), $cookies, $files, $server, $content);
415: }
416:
417: 418: 419: 420: 421: 422: 423: 424: 425:
426: public static function setFactory($callable)
427: {
428: self::$requestFactory = $callable;
429: }
430:
431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444:
445: public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
446: {
447: $dup = clone $this;
448: if ($query !== null) {
449: $dup->query = new ParameterBag($query);
450: }
451: if ($request !== null) {
452: $dup->request = new ParameterBag($request);
453: }
454: if ($attributes !== null) {
455: $dup->attributes = new ParameterBag($attributes);
456: }
457: if ($cookies !== null) {
458: $dup->cookies = new ParameterBag($cookies);
459: }
460: if ($files !== null) {
461: $dup->files = new FileBag($files);
462: }
463: if ($server !== null) {
464: $dup->server = new ServerBag($server);
465: $dup->headers = new HeaderBag($dup->server->getHeaders());
466: }
467: $dup->languages = null;
468: $dup->charsets = null;
469: $dup->encodings = null;
470: $dup->acceptableContentTypes = null;
471: $dup->pathInfo = null;
472: $dup->requestUri = null;
473: $dup->baseUrl = null;
474: $dup->basePath = null;
475: $dup->method = null;
476: $dup->format = null;
477:
478: if (!$dup->get('_format') && $this->get('_format')) {
479: $dup->attributes->set('_format', $this->get('_format'));
480: }
481:
482: if (!$dup->getRequestFormat(null)) {
483: $dup->setRequestFormat($this->getRequestFormat(null));
484: }
485:
486: return $dup;
487: }
488:
489: 490: 491: 492: 493: 494:
495: public function __clone()
496: {
497: $this->query = clone $this->query;
498: $this->request = clone $this->request;
499: $this->attributes = clone $this->attributes;
500: $this->cookies = clone $this->cookies;
501: $this->files = clone $this->files;
502: $this->server = clone $this->server;
503: $this->headers = clone $this->headers;
504: }
505:
506: 507: 508: 509: 510:
511: public function __toString()
512: {
513: return
514: sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
515: $this->headers."\r\n".
516: $this->getContent();
517: }
518:
519: 520: 521: 522: 523: 524: 525: 526:
527: public function overrideGlobals()
528: {
529: $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), null, '&')));
530:
531: $_GET = $this->query->all();
532: $_POST = $this->request->all();
533: $_SERVER = $this->server->all();
534: $_COOKIE = $this->cookies->all();
535:
536: foreach ($this->headers->all() as $key => $value) {
537: $key = strtoupper(str_replace('-', '_', $key));
538: if (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
539: $_SERVER[$key] = implode(', ', $value);
540: } else {
541: $_SERVER['HTTP_'.$key] = implode(', ', $value);
542: }
543: }
544:
545: $request = array('g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE);
546:
547: $requestOrder = ini_get('request_order') ?: ini_get('variables_order');
548: $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
549:
550: $_REQUEST = array();
551: foreach (str_split($requestOrder) as $order) {
552: $_REQUEST = array_merge($_REQUEST, $request[$order]);
553: }
554: }
555:
556: 557: 558: 559: 560: 561: 562: 563: 564:
565: public static function setTrustedProxies(array $proxies)
566: {
567: self::$trustedProxies = $proxies;
568: }
569:
570: 571: 572: 573: 574:
575: public static function getTrustedProxies()
576: {
577: return self::$trustedProxies;
578: }
579:
580: 581: 582: 583: 584: 585: 586:
587: public static function setTrustedHosts(array $hostPatterns)
588: {
589: self::$trustedHostPatterns = array_map(function ($hostPattern) {
590: return sprintf('{%s}i', str_replace('}', '\\}', $hostPattern));
591: }, $hostPatterns);
592:
593: self::$trustedHosts = array();
594: }
595:
596: 597: 598: 599: 600:
601: public static function getTrustedHosts()
602: {
603: return self::$trustedHostPatterns;
604: }
605:
606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622:
623: public static function setTrustedHeaderName($key, $value)
624: {
625: if (!array_key_exists($key, self::$trustedHeaders)) {
626: throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
627: }
628:
629: self::$trustedHeaders[$key] = $value;
630: }
631:
632: 633: 634: 635: 636: 637: 638: 639: 640:
641: public static function getTrustedHeaderName($key)
642: {
643: if (!array_key_exists($key, self::$trustedHeaders)) {
644: throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key));
645: }
646:
647: return self::$trustedHeaders[$key];
648: }
649:
650: 651: 652: 653: 654: 655: 656: 657: 658: 659:
660: public static function normalizeQueryString($qs)
661: {
662: if ('' == $qs) {
663: return '';
664: }
665:
666: $parts = array();
667: $order = array();
668:
669: foreach (explode('&', $qs) as $param) {
670: if ('' === $param || '=' === $param[0]) {
671:
672:
673:
674: continue;
675: }
676:
677: $keyValuePair = explode('=', $param, 2);
678:
679:
680:
681:
682: $parts[] = isset($keyValuePair[1]) ?
683: rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) :
684: rawurlencode(urldecode($keyValuePair[0]));
685: $order[] = urldecode($keyValuePair[0]);
686: }
687:
688: array_multisort($order, SORT_ASC, $parts);
689:
690: return implode('&', $parts);
691: }
692:
693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703:
704: public static function enableHttpMethodParameterOverride()
705: {
706: self::$httpMethodParameterOverride = true;
707: }
708:
709: 710: 711: 712: 713:
714: public static function getHttpMethodParameterOverride()
715: {
716: return self::$httpMethodParameterOverride;
717: }
718:
719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739:
740: public function get($key, $default = null, $deep = false)
741: {
742: if ($this !== $result = $this->query->get($key, $this, $deep)) {
743: return $result;
744: }
745:
746: if ($this !== $result = $this->attributes->get($key, $this, $deep)) {
747: return $result;
748: }
749:
750: if ($this !== $result = $this->request->get($key, $this, $deep)) {
751: return $result;
752: }
753:
754: return $default;
755: }
756:
757: 758: 759: 760: 761: 762: 763:
764: public function getSession()
765: {
766: return $this->session;
767: }
768:
769: 770: 771: 772: 773: 774: 775: 776:
777: public function hasPreviousSession()
778: {
779:
780: return $this->hasSession() && $this->cookies->has($this->session->getName());
781: }
782:
783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793:
794: public function hasSession()
795: {
796: return null !== $this->session;
797: }
798:
799: 800: 801: 802: 803: 804: 805:
806: public function setSession(SessionInterface $session)
807: {
808: $this->session = $session;
809: }
810:
811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823:
824: public function getClientIps()
825: {
826: $ip = $this->server->get('REMOTE_ADDR');
827:
828: if (!self::$trustedProxies) {
829: return array($ip);
830: }
831:
832: if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
833: return array($ip);
834: }
835:
836: $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
837: $clientIps[] = $ip;
838:
839: $ip = $clientIps[0];
840:
841:
842: foreach ($clientIps as $key => $clientIp) {
843:
844: if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
845: $clientIps[$key] = $clientIp = $match[1];
846: }
847:
848: if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
849: unset($clientIps[$key]);
850: }
851: }
852:
853:
854: return $clientIps ? array_reverse($clientIps) : array($ip);
855: }
856:
857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876:
877: public function getClientIp()
878: {
879: $ipAddresses = $this->getClientIps();
880:
881: return $ipAddresses[0];
882: }
883:
884: 885: 886: 887: 888: 889: 890:
891: public function getScriptName()
892: {
893: return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', ''));
894: }
895:
896: 897: 898: 899: 900: 901: 902: 903: 904: 905: 906: 907: 908: 909: 910: 911:
912: public function getPathInfo()
913: {
914: if (null === $this->pathInfo) {
915: $this->pathInfo = $this->preparePathInfo();
916: }
917:
918: return $this->pathInfo;
919: }
920:
921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934:
935: public function getBasePath()
936: {
937: if (null === $this->basePath) {
938: $this->basePath = $this->prepareBasePath();
939: }
940:
941: return $this->basePath;
942: }
943:
944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954: 955:
956: public function getBaseUrl()
957: {
958: if (null === $this->baseUrl) {
959: $this->baseUrl = $this->prepareBaseUrl();
960: }
961:
962: return $this->baseUrl;
963: }
964:
965: 966: 967: 968: 969: 970: 971:
972: public function getScheme()
973: {
974: return $this->isSecure() ? 'https' : 'http';
975: }
976:
977: 978: 979: 980: 981: 982: 983: 984: 985: 986: 987: 988: 989: 990: 991:
992: public function getPort()
993: {
994: if (self::$trustedProxies) {
995: if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) {
996: return $port;
997: }
998:
999: if (self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && 'https' === $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO], 'http')) {
1000: return 443;
1001: }
1002: }
1003:
1004: if ($host = $this->headers->get('HOST')) {
1005: if ($host[0] === '[') {
1006: $pos = strpos($host, ':', strrpos($host, ']'));
1007: } else {
1008: $pos = strrpos($host, ':');
1009: }
1010:
1011: if (false !== $pos) {
1012: return intval(substr($host, $pos + 1));
1013: }
1014:
1015: return 'https' === $this->getScheme() ? 443 : 80;
1016: }
1017:
1018: return $this->server->get('SERVER_PORT');
1019: }
1020:
1021: 1022: 1023: 1024: 1025:
1026: public function getUser()
1027: {
1028: return $this->headers->get('PHP_AUTH_USER');
1029: }
1030:
1031: 1032: 1033: 1034: 1035:
1036: public function getPassword()
1037: {
1038: return $this->headers->get('PHP_AUTH_PW');
1039: }
1040:
1041: 1042: 1043: 1044: 1045:
1046: public function getUserInfo()
1047: {
1048: $userinfo = $this->getUser();
1049:
1050: $pass = $this->getPassword();
1051: if ('' != $pass) {
1052: $userinfo .= ":$pass";
1053: }
1054:
1055: return $userinfo;
1056: }
1057:
1058: 1059: 1060: 1061: 1062: 1063: 1064: 1065: 1066:
1067: public function getHttpHost()
1068: {
1069: $scheme = $this->getScheme();
1070: $port = $this->getPort();
1071:
1072: if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) {
1073: return $this->getHost();
1074: }
1075:
1076: return $this->getHost().':'.$port;
1077: }
1078:
1079: 1080: 1081: 1082: 1083: 1084: 1085:
1086: public function getRequestUri()
1087: {
1088: if (null === $this->requestUri) {
1089: $this->requestUri = $this->prepareRequestUri();
1090: }
1091:
1092: return $this->requestUri;
1093: }
1094:
1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102:
1103: public function getSchemeAndHttpHost()
1104: {
1105: return $this->getScheme().'://'.$this->getHttpHost();
1106: }
1107:
1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116:
1117: public function getUri()
1118: {
1119: if (null !== $qs = $this->getQueryString()) {
1120: $qs = '?'.$qs;
1121: }
1122:
1123: return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
1124: }
1125:
1126: 1127: 1128: 1129: 1130: 1131: 1132: 1133: 1134:
1135: public function getUriForPath($path)
1136: {
1137: return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
1138: }
1139:
1140: 1141: 1142: 1143: 1144: 1145: 1146: 1147: 1148: 1149:
1150: public function getQueryString()
1151: {
1152: $qs = static::normalizeQueryString($this->server->get('QUERY_STRING'));
1153:
1154: return '' === $qs ? null : $qs;
1155: }
1156:
1157: 1158: 1159: 1160: 1161: 1162: 1163: 1164: 1165: 1166: 1167: 1168: 1169: 1170: 1171: 1172:
1173: public function isSecure()
1174: {
1175: if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
1176: return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));
1177: }
1178:
1179: $https = $this->server->get('HTTPS');
1180:
1181: return !empty($https) && 'off' !== strtolower($https);
1182: }
1183:
1184: 1185: 1186: 1187: 1188: 1189: 1190: 1191: 1192: 1193: 1194: 1195: 1196: 1197: 1198: 1199: 1200:
1201: public function getHost()
1202: {
1203: if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) {
1204: $elements = explode(',', $host);
1205:
1206: $host = $elements[count($elements) - 1];
1207: } elseif (!$host = $this->headers->get('HOST')) {
1208: if (!$host = $this->server->get('SERVER_NAME')) {
1209: $host = $this->server->get('SERVER_ADDR', '');
1210: }
1211: }
1212:
1213:
1214:
1215: $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
1216:
1217:
1218:
1219:
1220: if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) {
1221: throw new \UnexpectedValueException(sprintf('Invalid Host "%s"', $host));
1222: }
1223:
1224: if (count(self::$trustedHostPatterns) > 0) {
1225:
1226:
1227: if (in_array($host, self::$trustedHosts)) {
1228: return $host;
1229: }
1230:
1231: foreach (self::$trustedHostPatterns as $pattern) {
1232: if (preg_match($pattern, $host)) {
1233: self::$trustedHosts[] = $host;
1234:
1235: return $host;
1236: }
1237: }
1238:
1239: throw new \UnexpectedValueException(sprintf('Untrusted Host "%s"', $host));
1240: }
1241:
1242: return $host;
1243: }
1244:
1245: 1246: 1247: 1248: 1249: 1250: 1251:
1252: public function setMethod($method)
1253: {
1254: $this->method = null;
1255: $this->server->set('REQUEST_METHOD', $method);
1256: }
1257:
1258: 1259: 1260: 1261: 1262: 1263: 1264: 1265: 1266: 1267: 1268: 1269: 1270: 1271: 1272: 1273: 1274:
1275: public function getMethod()
1276: {
1277: if (null === $this->method) {
1278: $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
1279:
1280: if ('POST' === $this->method) {
1281: if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
1282: $this->method = strtoupper($method);
1283: } elseif (self::$httpMethodParameterOverride) {
1284: $this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
1285: }
1286: }
1287: }
1288:
1289: return $this->method;
1290: }
1291:
1292: 1293: 1294: 1295: 1296: 1297: 1298:
1299: public function getRealMethod()
1300: {
1301: return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
1302: }
1303:
1304: 1305: 1306: 1307: 1308: 1309: 1310: 1311: 1312:
1313: public function getMimeType($format)
1314: {
1315: if (null === static::$formats) {
1316: static::initializeFormats();
1317: }
1318:
1319: return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
1320: }
1321:
1322: 1323: 1324: 1325: 1326: 1327: 1328: 1329: 1330:
1331: public function getFormat($mimeType)
1332: {
1333: if (false !== $pos = strpos($mimeType, ';')) {
1334: $mimeType = substr($mimeType, 0, $pos);
1335: }
1336:
1337: if (null === static::$formats) {
1338: static::initializeFormats();
1339: }
1340:
1341: foreach (static::$formats as $format => $mimeTypes) {
1342: if (in_array($mimeType, (array) $mimeTypes)) {
1343: return $format;
1344: }
1345: }
1346: }
1347:
1348: 1349: 1350: 1351: 1352: 1353: 1354: 1355:
1356: public function setFormat($format, $mimeTypes)
1357: {
1358: if (null === static::$formats) {
1359: static::initializeFormats();
1360: }
1361:
1362: static::$formats[$format] = is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
1363: }
1364:
1365: 1366: 1367: 1368: 1369: 1370: 1371: 1372: 1373: 1374: 1375: 1376: 1377: 1378: 1379:
1380: public function getRequestFormat($default = 'html')
1381: {
1382: if (null === $this->format) {
1383: $this->format = $this->get('_format', $default);
1384: }
1385:
1386: return $this->format;
1387: }
1388:
1389: 1390: 1391: 1392: 1393: 1394: 1395:
1396: public function setRequestFormat($format)
1397: {
1398: $this->format = $format;
1399: }
1400:
1401: 1402: 1403: 1404: 1405: 1406: 1407:
1408: public function getContentType()
1409: {
1410: return $this->getFormat($this->headers->get('CONTENT_TYPE'));
1411: }
1412:
1413: 1414: 1415: 1416: 1417: 1418: 1419:
1420: public function setDefaultLocale($locale)
1421: {
1422: $this->defaultLocale = $locale;
1423:
1424: if (null === $this->locale) {
1425: $this->setPhpDefaultLocale($locale);
1426: }
1427: }
1428:
1429: 1430: 1431: 1432: 1433:
1434: public function getDefaultLocale()
1435: {
1436: return $this->defaultLocale;
1437: }
1438:
1439: 1440: 1441: 1442: 1443: 1444: 1445:
1446: public function setLocale($locale)
1447: {
1448: $this->setPhpDefaultLocale($this->locale = $locale);
1449: }
1450:
1451: 1452: 1453: 1454: 1455:
1456: public function getLocale()
1457: {
1458: return null === $this->locale ? $this->defaultLocale : $this->locale;
1459: }
1460:
1461: 1462: 1463: 1464: 1465: 1466: 1467:
1468: public function isMethod($method)
1469: {
1470: return $this->getMethod() === strtoupper($method);
1471: }
1472:
1473: 1474: 1475: 1476: 1477: 1478: 1479:
1480: public function isMethodSafe()
1481: {
1482: return in_array($this->getMethod(), array('GET', 'HEAD'));
1483: }
1484:
1485: 1486: 1487: 1488: 1489: 1490: 1491: 1492: 1493:
1494: public function getContent($asResource = false)
1495: {
1496: if (false === $this->content || (true === $asResource && null !== $this->content)) {
1497: throw new \LogicException('getContent() can only be called once when using the resource return type.');
1498: }
1499:
1500: if (true === $asResource) {
1501: $this->content = false;
1502:
1503: return fopen('php://input', 'rb');
1504: }
1505:
1506: if (null === $this->content) {
1507: $this->content = file_get_contents('php://input');
1508: }
1509:
1510: return $this->content;
1511: }
1512:
1513: 1514: 1515: 1516: 1517:
1518: public function getETags()
1519: {
1520: return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, PREG_SPLIT_NO_EMPTY);
1521: }
1522:
1523: 1524: 1525:
1526: public function isNoCache()
1527: {
1528: return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma');
1529: }
1530:
1531: 1532: 1533: 1534: 1535: 1536: 1537: 1538: 1539:
1540: public function getPreferredLanguage(array $locales = null)
1541: {
1542: $preferredLanguages = $this->getLanguages();
1543:
1544: if (empty($locales)) {
1545: return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null;
1546: }
1547:
1548: if (!$preferredLanguages) {
1549: return $locales[0];
1550: }
1551:
1552: $extendedPreferredLanguages = array();
1553: foreach ($preferredLanguages as $language) {
1554: $extendedPreferredLanguages[] = $language;
1555: if (false !== $position = strpos($language, '_')) {
1556: $superLanguage = substr($language, 0, $position);
1557: if (!in_array($superLanguage, $preferredLanguages)) {
1558: $extendedPreferredLanguages[] = $superLanguage;
1559: }
1560: }
1561: }
1562:
1563: $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
1564:
1565: return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
1566: }
1567:
1568: 1569: 1570: 1571: 1572: 1573: 1574:
1575: public function getLanguages()
1576: {
1577: if (null !== $this->languages) {
1578: return $this->languages;
1579: }
1580:
1581: $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
1582: $this->languages = array();
1583: foreach (array_keys($languages) as $lang) {
1584: if (strstr($lang, '-')) {
1585: $codes = explode('-', $lang);
1586: if ($codes[0] == 'i') {
1587:
1588:
1589:
1590: if (count($codes) > 1) {
1591: $lang = $codes[1];
1592: }
1593: } else {
1594: for ($i = 0, $max = count($codes); $i < $max; $i++) {
1595: if ($i == 0) {
1596: $lang = strtolower($codes[0]);
1597: } else {
1598: $lang .= '_'.strtoupper($codes[$i]);
1599: }
1600: }
1601: }
1602: }
1603:
1604: $this->languages[] = $lang;
1605: }
1606:
1607: return $this->languages;
1608: }
1609:
1610: 1611: 1612: 1613: 1614: 1615: 1616:
1617: public function getCharsets()
1618: {
1619: if (null !== $this->charsets) {
1620: return $this->charsets;
1621: }
1622:
1623: return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
1624: }
1625:
1626: 1627: 1628: 1629: 1630:
1631: public function getEncodings()
1632: {
1633: if (null !== $this->encodings) {
1634: return $this->encodings;
1635: }
1636:
1637: return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all());
1638: }
1639:
1640: 1641: 1642: 1643: 1644: 1645: 1646:
1647: public function getAcceptableContentTypes()
1648: {
1649: if (null !== $this->acceptableContentTypes) {
1650: return $this->acceptableContentTypes;
1651: }
1652:
1653: return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
1654: }
1655:
1656: 1657: 1658: 1659: 1660: 1661: 1662: 1663: 1664: 1665: 1666: 1667:
1668: public function isXmlHttpRequest()
1669: {
1670: return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
1671: }
1672:
1673: 1674: 1675: 1676: 1677: 1678: 1679:
1680:
1681: protected function prepareRequestUri()
1682: {
1683: $requestUri = '';
1684:
1685: if ($this->headers->has('X_ORIGINAL_URL')) {
1686:
1687: $requestUri = $this->headers->get('X_ORIGINAL_URL');
1688: $this->headers->remove('X_ORIGINAL_URL');
1689: $this->server->remove('HTTP_X_ORIGINAL_URL');
1690: $this->server->remove('UNENCODED_URL');
1691: $this->server->remove('IIS_WasUrlRewritten');
1692: } elseif ($this->headers->has('X_REWRITE_URL')) {
1693:
1694: $requestUri = $this->headers->get('X_REWRITE_URL');
1695: $this->headers->remove('X_REWRITE_URL');
1696: } elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
1697:
1698: $requestUri = $this->server->get('UNENCODED_URL');
1699: $this->server->remove('UNENCODED_URL');
1700: $this->server->remove('IIS_WasUrlRewritten');
1701: } elseif ($this->server->has('REQUEST_URI')) {
1702: $requestUri = $this->server->get('REQUEST_URI');
1703:
1704: $schemeAndHttpHost = $this->getSchemeAndHttpHost();
1705: if (strpos($requestUri, $schemeAndHttpHost) === 0) {
1706: $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
1707: }
1708: } elseif ($this->server->has('ORIG_PATH_INFO')) {
1709:
1710: $requestUri = $this->server->get('ORIG_PATH_INFO');
1711: if ('' != $this->server->get('QUERY_STRING')) {
1712: $requestUri .= '?'.$this->server->get('QUERY_STRING');
1713: }
1714: $this->server->remove('ORIG_PATH_INFO');
1715: }
1716:
1717:
1718: $this->server->set('REQUEST_URI', $requestUri);
1719:
1720: return $requestUri;
1721: }
1722:
1723: 1724: 1725: 1726: 1727:
1728: protected function prepareBaseUrl()
1729: {
1730: $filename = basename($this->server->get('SCRIPT_FILENAME'));
1731:
1732: if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
1733: $baseUrl = $this->server->get('SCRIPT_NAME');
1734: } elseif (basename($this->server->get('PHP_SELF')) === $filename) {
1735: $baseUrl = $this->server->get('PHP_SELF');
1736: } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
1737: $baseUrl = $this->server->get('ORIG_SCRIPT_NAME');
1738: } else {
1739:
1740:
1741: $path = $this->server->get('PHP_SELF', '');
1742: $file = $this->server->get('SCRIPT_FILENAME', '');
1743: $segs = explode('/', trim($file, '/'));
1744: $segs = array_reverse($segs);
1745: $index = 0;
1746: $last = count($segs);
1747: $baseUrl = '';
1748: do {
1749: $seg = $segs[$index];
1750: $baseUrl = '/'.$seg.$baseUrl;
1751: ++$index;
1752: } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos);
1753: }
1754:
1755:
1756: $requestUri = $this->getRequestUri();
1757:
1758: if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
1759:
1760: return $prefix;
1761: }
1762:
1763: if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, dirname($baseUrl).'/')) {
1764:
1765: return rtrim($prefix, '/');
1766: }
1767:
1768: $truncatedRequestUri = $requestUri;
1769: if (false !== $pos = strpos($requestUri, '?')) {
1770: $truncatedRequestUri = substr($requestUri, 0, $pos);
1771: }
1772:
1773: $basename = basename($baseUrl);
1774: if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
1775:
1776: return '';
1777: }
1778:
1779:
1780:
1781:
1782: if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && $pos !== 0) {
1783: $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
1784: }
1785:
1786: return rtrim($baseUrl, '/');
1787: }
1788:
1789: 1790: 1791: 1792: 1793:
1794: protected function prepareBasePath()
1795: {
1796: $filename = basename($this->server->get('SCRIPT_FILENAME'));
1797: $baseUrl = $this->getBaseUrl();
1798: if (empty($baseUrl)) {
1799: return '';
1800: }
1801:
1802: if (basename($baseUrl) === $filename) {
1803: $basePath = dirname($baseUrl);
1804: } else {
1805: $basePath = $baseUrl;
1806: }
1807:
1808: if ('\\' === DIRECTORY_SEPARATOR) {
1809: $basePath = str_replace('\\', '/', $basePath);
1810: }
1811:
1812: return rtrim($basePath, '/');
1813: }
1814:
1815: 1816: 1817: 1818: 1819:
1820: protected function preparePathInfo()
1821: {
1822: $baseUrl = $this->getBaseUrl();
1823:
1824: if (null === ($requestUri = $this->getRequestUri())) {
1825: return '/';
1826: }
1827:
1828: $pathInfo = '/';
1829:
1830:
1831: if ($pos = strpos($requestUri, '?')) {
1832: $requestUri = substr($requestUri, 0, $pos);
1833: }
1834:
1835: if (null !== $baseUrl && false === $pathInfo = substr($requestUri, strlen($baseUrl))) {
1836:
1837: return '/';
1838: } elseif (null === $baseUrl) {
1839: return $requestUri;
1840: }
1841:
1842: return (string) $pathInfo;
1843: }
1844:
1845: 1846: 1847:
1848: protected static function initializeFormats()
1849: {
1850: static::$formats = array(
1851: 'html' => array('text/html', 'application/xhtml+xml'),
1852: 'txt' => array('text/plain'),
1853: 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
1854: 'css' => array('text/css'),
1855: 'json' => array('application/json', 'application/x-json'),
1856: 'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
1857: 'rdf' => array('application/rdf+xml'),
1858: 'atom' => array('application/atom+xml'),
1859: 'rss' => array('application/rss+xml'),
1860: 'form' => array('application/x-www-form-urlencoded'),
1861: );
1862: }
1863:
1864: 1865: 1866: 1867: 1868:
1869: private function setPhpDefaultLocale($locale)
1870: {
1871:
1872:
1873:
1874: try {
1875: if (class_exists('Locale', false)) {
1876: \Locale::setDefault($locale);
1877: }
1878: } catch (\Exception $e) {
1879: }
1880: }
1881:
1882: 1883: 1884: 1885: 1886: 1887: 1888: 1889: 1890:
1891: private function getUrlencodedPrefix($string, $prefix)
1892: {
1893: if (0 !== strpos(rawurldecode($string), $prefix)) {
1894: return false;
1895: }
1896:
1897: $len = strlen($prefix);
1898:
1899: if (preg_match("#^(%[[:xdigit:]]{2}|.){{$len}}#", $string, $match)) {
1900: return $match[0];
1901: }
1902:
1903: return false;
1904: }
1905:
1906: private static function createRequestFromFactory(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
1907: {
1908: if (self::$requestFactory) {
1909: $request = call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
1910:
1911: if (!$request instanceof Request) {
1912: throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
1913: }
1914:
1915: return $request;
1916: }
1917:
1918: return new static($query, $request, $attributes, $cookies, $files, $server, $content);
1919: }
1920: }
1921: