Request.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. <?php
  2. namespace Symfony\Components\HttpKernel;
  3. /*
  4. * This file is part of the Symfony package.
  5. *
  6. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. /**
  12. * Request represents an HTTP request.
  13. *
  14. * @package Symfony
  15. * @subpackage Components_HttpKernel
  16. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  17. */
  18. class Request
  19. {
  20. public $path;
  21. public $request;
  22. public $query;
  23. public $server;
  24. public $files;
  25. public $cookies;
  26. public $headers;
  27. protected $languages;
  28. protected $charsets;
  29. protected $acceptableContentTypes;
  30. protected $pathInfo;
  31. protected $requestUri;
  32. protected $baseUrl;
  33. protected $basePath;
  34. protected $method;
  35. protected $format;
  36. static protected $formats;
  37. /**
  38. * Constructor.
  39. *
  40. * @param array $query The GET parameters
  41. * @param array $request The POST parameters
  42. * @param array $path The parameters parsed from the PATH_INFO (see Router)
  43. * @param array $cookies The COOKIE parameters
  44. * @param array $files The FILES parameters
  45. * @param array $server The SERVER parameters
  46. */
  47. public function __construct(array $query = null, array $request = null, array $path = null, array $cookies = null, array $files = null, array $server = null)
  48. {
  49. $this->initialize($request, $query, $path, $cookies, $files, $server);
  50. }
  51. /**
  52. * Sets the parameters for this request.
  53. *
  54. * This method also re-initializes all properties.
  55. *
  56. * @param array $query The GET parameters
  57. * @param array $request The POST parameters
  58. * @param array $path The parameters parsed from the PATH_INFO
  59. * @param array $cookies The COOKIE parameters
  60. * @param array $files The FILES parameters
  61. * @param array $server The SERVER parameters
  62. */
  63. public function initialize(array $query = null, array $request = null, array $path = null, array $cookies = null, array $files = null, array $server = null)
  64. {
  65. $this->request = new ParameterBag(null !== $request ? $request : $_POST);
  66. $this->query = new ParameterBag(null !== $query ? $query : $_GET);
  67. $this->path = new ParameterBag(null !== $path ? $path : array());
  68. $this->cookies = new ParameterBag(null !== $cookies ? $cookies : $_COOKIE);
  69. $this->files = new ParameterBag($this->convertFileInformation(null !== $files ? $files : $_FILES));
  70. $this->server = new ParameterBag(null !== $server ? $server : $_SERVER);
  71. $this->headers = new HeaderBag($this->initializeHeaders(), 'request');
  72. $this->languages = null;
  73. $this->charsets = null;
  74. $this->acceptableContentTypes = null;
  75. $this->pathInfo = null;
  76. $this->requestUri = null;
  77. $this->baseUrl = null;
  78. $this->basePath = null;
  79. $this->method = null;
  80. $this->format = null;
  81. }
  82. /**
  83. * Creates a Request based on a given URI and configuration.
  84. *
  85. * @param string $uri The URI
  86. * @param string $method The HTTP method
  87. * @param array $parameters The request (GET) or query (POST) parameters
  88. * @param array $cookies The request cookies ($_COOKIE)
  89. * @param array $files The request files ($_FILES)
  90. * @param array $server The server parameters ($_SERVER)
  91. *
  92. * @return Request A Request instance
  93. */
  94. static public function create($uri, $method = 'get', $parameters = array(), $cookies = array(), $files = array(), $server = array())
  95. {
  96. $defaults = array(
  97. 'SERVER_NAME' => 'localhost',
  98. 'SERVER_PORT' => 80,
  99. 'HTTP_HOST' => 'localhost',
  100. 'HTTP_USER_AGENT' => 'Symfony/X.X',
  101. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  102. 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
  103. 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
  104. 'REMOTE_ADDR' => '127.0.0.1',
  105. 'SCRIPT_NAME' => '',
  106. 'SCRIPT_FILENAME' => '',
  107. );
  108. if (in_array(strtolower($method), array('post', 'put', 'delete'))) {
  109. $request = $parameters;
  110. $query = array();
  111. $defaults['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
  112. } else {
  113. $request = array();
  114. $query = $parameters;
  115. if (false !== $pos = strpos($uri, '?')) {
  116. $qs = substr($uri, $pos + 1);
  117. parse_str($qs, $params);
  118. $query = array_merge($params, $query);
  119. }
  120. }
  121. $queryString = false !== ($pos = strpos($uri, '?')) ? html_entity_decode(substr($uri, $pos + 1)) : '';
  122. parse_str($queryString, $qs);
  123. if (is_array($qs)) {
  124. $query = array_replace($qs, $query);
  125. }
  126. $server = array_replace($defaults, $server, array(
  127. 'REQUEST_METHOD' => strtoupper($method),
  128. 'PATH_INFO' => '',
  129. 'REQUEST_URI' => $uri,
  130. 'QUERY_STRING' => $queryString,
  131. ));
  132. return new self($query, $request, array(), $cookies, $files, $server);
  133. }
  134. /**
  135. * Clones a request and overrides some of its parameters.
  136. *
  137. * @param array $query The GET parameters
  138. * @param array $request The POST parameters
  139. * @param array $path The parameters parsed from the PATH_INFO
  140. * @param array $cookies The COOKIE parameters
  141. * @param array $files The FILES parameters
  142. * @param array $server The SERVER parameters
  143. */
  144. public function duplicate(array $query = null, array $request = null, array $path = null, array $cookies = null, array $files = null, array $server = null)
  145. {
  146. $dup = clone $this;
  147. $dup->initialize(
  148. null !== $query ? $query : $this->query->all(),
  149. null !== $request ? $request : $this->request->all(),
  150. null !== $path ? $path : $this->path->all(),
  151. null !== $cookies ? $cookies : $this->cookies->all(),
  152. null !== $files ? $files : $this->files->all(),
  153. null !== $server ? $server : $this->server->all()
  154. );
  155. return $dup;
  156. }
  157. public function __clone()
  158. {
  159. $this->query = clone $this->query;
  160. $this->request = clone $this->request;
  161. $this->path = clone $this->path;
  162. $this->cookies = clone $this->cookies;
  163. $this->files = clone $this->files;
  164. $this->server = clone $this->server;
  165. $this->headers = clone $this->headers;
  166. }
  167. /**
  168. * Overrides the PHP global variables according to this request instance.
  169. *
  170. * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIES, and $_FILES.
  171. */
  172. public function overrideGlobals()
  173. {
  174. $_GET = $this->query->all();
  175. $_POST = $this->request->all();
  176. $_SERVER = $this->server->all();
  177. $_COOKIES = $this->cookies->all();
  178. // FIXME: populate $_FILES
  179. // FIXME: should read variables_order and request_order
  180. // to know which globals to merge and in which order
  181. $_REQUEST = array_merge($_GET, $_POST);
  182. }
  183. // Order of precedence: GET, PATH, POST, COOKIE
  184. // Avoid using this method in controllers:
  185. // * slow
  186. // * prefer to get from a "named" source
  187. // This method is mainly useful for libraries that want to provide some flexibility
  188. public function get($key, $default = null)
  189. {
  190. return $this->query->get($key, $this->path->get($key, $this->request->get($key, $default)));
  191. }
  192. /**
  193. * Returns current script name.
  194. *
  195. * @return string
  196. */
  197. public function getScriptName()
  198. {
  199. return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', ''));
  200. }
  201. public function getPathInfo()
  202. {
  203. if (null === $this->pathInfo) {
  204. $this->pathInfo = $this->preparePathInfo();
  205. }
  206. return $this->pathInfo;
  207. }
  208. public function getBasePath()
  209. {
  210. if (null === $this->basePath) {
  211. $this->basePath = $this->prepareBasePath();
  212. }
  213. return $this->basePath;
  214. }
  215. public function getBaseUrl()
  216. {
  217. if (null === $this->baseUrl) {
  218. $this->baseUrl = $this->prepareBaseUrl();
  219. }
  220. return $this->baseUrl;
  221. }
  222. public function getScheme()
  223. {
  224. return ($this->server->get('HTTPS') == 'on') ? 'https' : 'http';
  225. }
  226. public function getPort()
  227. {
  228. return $this->server->get('SERVER_PORT');
  229. }
  230. public function getHttpHost()
  231. {
  232. $host = $this->headers->get('HOST');
  233. if (!empty($host)) {
  234. return $host;
  235. }
  236. $scheme = $this->getScheme();
  237. $name = $this->server->get('SERVER_NAME');
  238. $port = $this->server->get('SERVER_PORT');
  239. if (($scheme === 'http' && $port === 80) || ($scheme === 'https' && $port === 443)) {
  240. return $name;
  241. } else {
  242. return $name.':'.$port;
  243. }
  244. }
  245. public function getRequestUri()
  246. {
  247. if (null === $this->requestUri) {
  248. $this->requestUri = $this->prepareRequestUri();
  249. }
  250. return $this->requestUri;
  251. }
  252. /**
  253. * Generates a normalized URI for the Request.
  254. *
  255. * @return string A normalized URI for the Request
  256. *
  257. * @see getQueryString()
  258. */
  259. public function getUri()
  260. {
  261. $qs = $this->getQueryString();
  262. if (null !== $qs) {
  263. $qs = '?'.$qs;
  264. }
  265. return $this->getScheme().'://'.$this->getHost().':'.$this->getPort().$this->getScriptName().$this->getPathInfo().$qs;
  266. }
  267. /**
  268. * Generates the normalized query string for the Request.
  269. *
  270. * It builds a normalized query string, where keys/value pairs are alphabetized
  271. * and have consistent escaping.
  272. *
  273. * @return string A normalized query string for the Request
  274. */
  275. public function getQueryString()
  276. {
  277. if (!$qs = $this->server->get('QUERY_STRING')) {
  278. return null;
  279. }
  280. $parts = array();
  281. foreach (explode('&', $qs) as $segment) {
  282. $tmp = explode('=', urldecode($segment), 2);
  283. $parts[urlencode($tmp[0])] = urlencode($tmp[1]);
  284. }
  285. ksort($parts);
  286. $elements = array();
  287. foreach ($parts as $key => $value) {
  288. $elements[] = "$key=$value";
  289. }
  290. if (count($elements)) {
  291. return implode('&', $elements);
  292. }
  293. }
  294. public function isSecure()
  295. {
  296. return (
  297. (strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
  298. ||
  299. (strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
  300. ||
  301. (strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
  302. );
  303. }
  304. /**
  305. * Returns the host name.
  306. *
  307. * @return string
  308. */
  309. public function getHost()
  310. {
  311. if ($host = $this->headers->get('X_FORWARDED_HOST')) {
  312. $elements = implode(',', $host);
  313. return trim($elements[count($elements) - 1]);
  314. } else {
  315. return $this->headers->get('HOST', $this->server->get('SERVER_NAME', $this->server->get('SERVER_ADDR', '')));
  316. }
  317. }
  318. public function setMethod($method)
  319. {
  320. $this->method = null;
  321. $this->server->set('REQUEST_METHOD', 'GET');
  322. }
  323. /**
  324. * Gets the request method.
  325. *
  326. * @return string The request method
  327. */
  328. public function getMethod()
  329. {
  330. if (null === $this->method) {
  331. switch ($this->server->get('REQUEST_METHOD', 'GET')) {
  332. case 'POST':
  333. $this->method = strtoupper($this->request->get('_method', 'POST'));
  334. break;
  335. case 'PUT':
  336. $this->method = 'PUT';
  337. break;
  338. case 'DELETE':
  339. $this->method = 'DELETE';
  340. break;
  341. case 'HEAD':
  342. $this->method = 'HEAD';
  343. break;
  344. default:
  345. $this->method = 'GET';
  346. }
  347. }
  348. return $this->method;
  349. }
  350. /**
  351. * Gets the mime type associated with the format.
  352. *
  353. * @param string $format The format
  354. *
  355. * @return string The associated mime type (null if not found)
  356. */
  357. public function getMimeType($format)
  358. {
  359. if (null === static::$formats) {
  360. static::initializeFormats();
  361. }
  362. return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
  363. }
  364. /**
  365. * Gets the format associated with the mime type.
  366. *
  367. * @param string $mimeType The associated mime type
  368. *
  369. * @return string The format (null if not found)
  370. */
  371. public function getFormat($mimeType)
  372. {
  373. if (null === static::$formats) {
  374. static::initializeFormats();
  375. }
  376. foreach (static::$formats as $format => $mimeTypes) {
  377. if (in_array($mimeType, (array) $mimeTypes)) {
  378. return $format;
  379. }
  380. }
  381. return null;
  382. }
  383. /**
  384. * Associates a format with mime types.
  385. *
  386. * @param string $format The format
  387. * @param string|array $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
  388. */
  389. public function setFormat($format, $mimeTypes)
  390. {
  391. if (null === static::$formats) {
  392. static::initializeFormats();
  393. }
  394. static::$formats[$format] = is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
  395. }
  396. /**
  397. * Gets the request format.
  398. *
  399. * Here is the process to determine the format:
  400. *
  401. * * format defined by the user (with setRequestFormat())
  402. * * _format request parameter
  403. * * null
  404. *
  405. * @return string The request format
  406. */
  407. public function getRequestFormat()
  408. {
  409. if (null === $this->format) {
  410. $this->format = $this->get('_format', 'html');
  411. }
  412. return $this->format;
  413. }
  414. public function isMethodSafe()
  415. {
  416. return in_array(strtolower($this->getMethod()), array('get', 'head'));
  417. }
  418. public function getETags()
  419. {
  420. return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, PREG_SPLIT_NO_EMPTY);
  421. }
  422. public function isNoCache()
  423. {
  424. return $this->headers->getCacheControl()->isNoCache() || 'no-cache' == $this->headers->get('Pragma');
  425. }
  426. /**
  427. * Returns the preferred language.
  428. *
  429. * @param array $locales An array of ordered available locales
  430. *
  431. * @return string The preferred locale
  432. */
  433. public function getPreferredLanguage(array $locales = null)
  434. {
  435. $preferredLanguages = $this->getLanguages();
  436. if (null === $locales) {
  437. return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null;
  438. }
  439. if (!$preferredLanguages) {
  440. return $locales[0];
  441. }
  442. $preferredLanguages = array_values(array_intersect($preferredLanguages, $locales));
  443. return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
  444. }
  445. /**
  446. * Gets a list of languages acceptable by the client browser.
  447. *
  448. * @return array Languages ordered in the user browser preferences
  449. */
  450. public function getLanguages()
  451. {
  452. if (null !== $this->languages) {
  453. return $this->languages;
  454. }
  455. $languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language'));
  456. foreach ($languages as $lang) {
  457. if (strstr($lang, '-')) {
  458. $codes = explode('-', $lang);
  459. if ($codes[0] == 'i') {
  460. // Language not listed in ISO 639 that are not variants
  461. // of any listed language, which can be registered with the
  462. // i-prefix, such as i-cherokee
  463. if (count($codes) > 1) {
  464. $lang = $codes[1];
  465. }
  466. } else {
  467. for ($i = 0, $max = count($codes); $i < $max; $i++) {
  468. if ($i == 0) {
  469. $lang = strtolower($codes[0]);
  470. } else {
  471. $lang .= '_'.strtoupper($codes[$i]);
  472. }
  473. }
  474. }
  475. }
  476. $this->languages[] = $lang;
  477. }
  478. return $this->languages;
  479. }
  480. /**
  481. * Gets a list of charsets acceptable by the client browser.
  482. *
  483. * @return array List of charsets in preferable order
  484. */
  485. public function getCharsets()
  486. {
  487. if (null !== $this->charsets) {
  488. return $this->charsets;
  489. }
  490. return $this->charsets = $this->splitHttpAcceptHeader($this->headers->get('Accept-Charset'));
  491. }
  492. /**
  493. * Gets a list of content types acceptable by the client browser
  494. *
  495. * @return array Languages ordered in the user browser preferences
  496. */
  497. public function getAcceptableContentTypes()
  498. {
  499. if (null !== $this->acceptableContentTypes) {
  500. return $this->acceptableContentTypes;
  501. }
  502. return $this->acceptableContentTypes = $this->splitHttpAcceptHeader($this->headers->get('Accept'));
  503. }
  504. /**
  505. * Returns true if the request is a XMLHttpRequest.
  506. *
  507. * It works if your JavaScript library set an X-Requested-With HTTP header.
  508. * It is known to work with Prototype, Mootools, jQuery.
  509. *
  510. * @return bool true if the request is an XMLHttpRequest, false otherwise
  511. */
  512. public function isXmlHttpRequest()
  513. {
  514. return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
  515. }
  516. /**
  517. * Splits an Accept-* HTTP header.
  518. *
  519. * @param string $header Header to split
  520. */
  521. public function splitHttpAcceptHeader($header)
  522. {
  523. if (!$header) {
  524. return array();
  525. }
  526. $values = array();
  527. foreach (array_filter(explode(',', $header)) as $value) {
  528. // Cut off any q-value that might come after a semi-colon
  529. if ($pos = strpos($value, ';')) {
  530. $q = (float) trim(substr($value, strpos($value, '=') + 1));
  531. $value = trim(substr($value, 0, $pos));
  532. } else {
  533. $q = 1;
  534. }
  535. if (0 < $q) {
  536. $values[trim($value)] = $q;
  537. }
  538. }
  539. arsort($values);
  540. return array_keys($values);
  541. }
  542. /*
  543. * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
  544. *
  545. * Code subject to the new BSD license (http://framework.zend.com/license/new-bsd).
  546. *
  547. * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  548. */
  549. protected function prepareRequestUri()
  550. {
  551. $requestUri = '';
  552. if ($this->headers->has('X_REWRITE_URL')) {
  553. // check this first so IIS will catch
  554. $requestUri = $this->headers->get('X_REWRITE_URL');
  555. } elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
  556. // IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
  557. $requestUri = $this->server->get('UNENCODED_URL');
  558. } elseif ($this->server->has('REQUEST_URI')) {
  559. $requestUri = $this->server->get('REQUEST_URI');
  560. // HTTP proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
  561. $schemeAndHttpHost = $this->getScheme().'://'.$this->getHttpHost();
  562. if (strpos($requestUri, $schemeAndHttpHost) === 0) {
  563. $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
  564. }
  565. } elseif ($this->server->has('ORIG_PATH_INFO')) {
  566. // IIS 5.0, PHP as CGI
  567. $requestUri = $this->server->get('ORIG_PATH_INFO');
  568. if ($this->server->get('QUERY_STRING')) {
  569. $requestUri .= '?'.$this->server->get('QUERY_STRING');
  570. }
  571. }
  572. return $requestUri;
  573. }
  574. protected function prepareBaseUrl()
  575. {
  576. $baseUrl = '';
  577. $filename = basename($this->server->get('SCRIPT_FILENAME'));
  578. if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
  579. $baseUrl = $this->server->get('SCRIPT_NAME');
  580. } elseif (basename($this->server->get('PHP_SELF')) === $filename) {
  581. $baseUrl = $this->server->get('PHP_SELF');
  582. } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
  583. $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility
  584. } else {
  585. // Backtrack up the script_filename to find the portion matching
  586. // php_self
  587. $path = $this->server->get('PHP_SELF', '');
  588. $file = $this->server->get('SCRIPT_FILENAME', '');
  589. $segs = explode('/', trim($file, '/'));
  590. $segs = array_reverse($segs);
  591. $index = 0;
  592. $last = count($segs);
  593. $baseUrl = '';
  594. do {
  595. $seg = $segs[$index];
  596. $baseUrl = '/'.$seg.$baseUrl;
  597. ++$index;
  598. } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
  599. }
  600. // Does the baseUrl have anything in common with the request_uri?
  601. $requestUri = $this->getRequestUri();
  602. if ($baseUrl && 0 === strpos($requestUri, $baseUrl)) {
  603. // full $baseUrl matches
  604. return $baseUrl;
  605. }
  606. if ($baseUrl && 0 === strpos($requestUri, dirname($baseUrl))) {
  607. // directory portion of $baseUrl matches
  608. return rtrim(dirname($baseUrl), '/');
  609. }
  610. $truncatedRequestUri = $requestUri;
  611. if (($pos = strpos($requestUri, '?')) !== false) {
  612. $truncatedRequestUri = substr($requestUri, 0, $pos);
  613. }
  614. $basename = basename($baseUrl);
  615. if (empty($basename) || !strpos($truncatedRequestUri, $basename)) {
  616. // no match whatsoever; set it blank
  617. return '';
  618. }
  619. // If using mod_rewrite or ISAPI_Rewrite strip the script filename
  620. // out of baseUrl. $pos !== 0 makes sure it is not matching a value
  621. // from PATH_INFO or QUERY_STRING
  622. if ((strlen($requestUri) >= strlen($baseUrl)) && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) {
  623. $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
  624. }
  625. return rtrim($baseUrl, '/');
  626. }
  627. protected function prepareBasePath()
  628. {
  629. $basePath = '';
  630. $filename = basename($this->server->get('SCRIPT_FILENAME'));
  631. $baseUrl = $this->getBaseUrl();
  632. if (empty($baseUrl)) {
  633. return '';
  634. }
  635. if (basename($baseUrl) === $filename) {
  636. $basePath = dirname($baseUrl);
  637. } else {
  638. $basePath = $baseUrl;
  639. }
  640. if ('\\' === DIRECTORY_SEPARATOR) {
  641. $basePath = str_replace('\\', '/', $basePath);
  642. }
  643. return rtrim($basePath, '/');
  644. }
  645. protected function preparePathInfo()
  646. {
  647. $baseUrl = $this->getBaseUrl();
  648. if (null === ($requestUri = $this->getRequestUri())) {
  649. return '';
  650. }
  651. $pathInfo = '';
  652. // Remove the query string from REQUEST_URI
  653. if ($pos = strpos($requestUri, '?')) {
  654. $requestUri = substr($requestUri, 0, $pos);
  655. }
  656. if ((null !== $baseUrl) && (false === ($pathInfo = substr($requestUri, strlen($baseUrl))))) {
  657. // If substr() returns false then PATH_INFO is set to an empty string
  658. return '';
  659. } elseif (null === $baseUrl) {
  660. return $requestUri;
  661. }
  662. return (string) $pathInfo;
  663. }
  664. /**
  665. * Converts uploaded file array to a format following the $_GET and $POST naming convention.
  666. *
  667. * It's safe to pass an already converted array, in which case this method just returns the original array unmodified.
  668. *
  669. * @param array $taintedFiles An array representing uploaded file information
  670. *
  671. * @return array An array of re-ordered uploaded file information
  672. */
  673. protected function convertFileInformation(array $taintedFiles)
  674. {
  675. $files = array();
  676. foreach ($taintedFiles as $key => $data) {
  677. $files[$key] = $this->fixPhpFilesArray($data);
  678. }
  679. return $files;
  680. }
  681. protected function initializeHeaders()
  682. {
  683. $headers = array();
  684. foreach ($this->server->all() as $key => $value) {
  685. if ('http_' === strtolower(substr($key, 0, 5))) {
  686. $headers[substr($key, 5)] = $value;
  687. }
  688. }
  689. return $headers;
  690. }
  691. static protected function initializeFormats()
  692. {
  693. static::$formats = array(
  694. 'txt' => 'text/plain',
  695. 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
  696. 'css' => 'text/css',
  697. 'json' => array('application/json', 'application/x-json'),
  698. 'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
  699. 'rdf' => 'application/rdf+xml',
  700. 'atom' => 'application/atom+xml',
  701. );
  702. }
  703. static protected function fixPhpFilesArray($data)
  704. {
  705. $fileKeys = array('error', 'name', 'size', 'tmp_name', 'type');
  706. $keys = array_keys($data);
  707. sort($keys);
  708. if ($fileKeys != $keys || !isset($data['name']) || !is_array($data['name'])) {
  709. return $data;
  710. }
  711. $files = $data;
  712. foreach ($fileKeys as $k) {
  713. unset($files[$k]);
  714. }
  715. foreach (array_keys($data['name']) as $key) {
  716. $files[$key] = self::fixPhpFilesArray(array(
  717. 'error' => $data['error'][$key],
  718. 'name' => $data['name'][$key],
  719. 'type' => $data['type'][$key],
  720. 'tmp_name' => $data['tmp_name'][$key],
  721. 'size' => $data['size'][$key],
  722. ));
  723. }
  724. return $files;
  725. }
  726. }