Request.php 28 KB

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