Elgg  Version 1.10
Request.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg\Http;
3 
38 class Request {
42  public $query;
43 
48  public $request;
49 
54  public $cookies;
55 
60  public $files;
61 
66  public $server;
67 
72  public $headers;
73 
77  protected $baseUrl = null;
78 
82  protected $requestUri = null;
83 
87  protected $pathInfo = null;
88 
98  public function __construct(array $query = array(), array $request = array(),
99  array $cookies = array(), array $files = array(), array $server = array()) {
101  }
102 
113  protected function initialize(array $query = array(), array $request = array(),
114  array $cookies = array(), array $files = array(), array $server = array()) {
115  $this->query = new \Elgg\Http\ParameterBag($this->stripSlashesIfMagicQuotes($query));
116  $this->request = new \Elgg\Http\ParameterBag($this->stripSlashesIfMagicQuotes($request));
117  $this->cookies = new \Elgg\Http\ParameterBag($this->stripSlashesIfMagicQuotes($cookies));
118  // Symfony uses FileBag so this will change in next Elgg version
119  $this->files = new \Elgg\Http\ParameterBag($files);
120  $this->server = new \Elgg\Http\ParameterBag($server);
121 
122  $headers = $this->prepareHeaders();
123  // Symfony uses HeaderBag so this will change in next Elgg version
124  $this->headers = new \Elgg\Http\ParameterBag($headers);
125  }
126 
132  public static function createFromGlobals() {
133  return new \Elgg\Http\Request($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
134  }
135 
151  public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array()) {
152  $server = array_merge(array(
153  'SERVER_NAME' => 'localhost',
154  'SERVER_PORT' => 80,
155  'HTTP_HOST' => 'localhost',
156  'HTTP_USER_AGENT' => 'Symfony/2.X',
157  'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
158  'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
159  'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
160  'REMOTE_ADDR' => '127.0.0.1',
161  'SCRIPT_NAME' => '',
162  'SCRIPT_FILENAME' => '',
163  'SERVER_PROTOCOL' => 'HTTP/1.1',
164  'REQUEST_TIME' => time(),
165  ), $server);
166 
167  $server['PATH_INFO'] = '';
168  $server['REQUEST_METHOD'] = strtoupper($method);
169 
170  $components = parse_url($uri);
171  if (isset($components['host'])) {
172  $server['SERVER_NAME'] = $components['host'];
173  $server['HTTP_HOST'] = $components['host'];
174  }
175 
176  if (isset($components['scheme'])) {
177  if ('https' === $components['scheme']) {
178  $server['HTTPS'] = 'on';
179  $server['SERVER_PORT'] = 443;
180  } else {
181  unset($server['HTTPS']);
182  $server['SERVER_PORT'] = 80;
183  }
184  }
185 
186  if (isset($components['port'])) {
187  $server['SERVER_PORT'] = $components['port'];
188  $server['HTTP_HOST'] = $server['HTTP_HOST'] . ':' . $components['port'];
189  }
190 
191  if (!isset($components['path'])) {
192  $components['path'] = '/';
193  }
194 
195  switch (strtoupper($method)) {
196  case 'POST':
197  case 'PUT':
198  case 'DELETE':
199  if (!isset($server['CONTENT_TYPE'])) {
200  $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
201  }
202  case 'PATCH':
203  $request = $parameters;
204  $query = array();
205  break;
206  default:
207  $request = array();
208  $query = $parameters;
209  break;
210  }
211 
212  if (isset($components['query'])) {
213  parse_str(html_entity_decode($components['query']), $qs);
214  // original uses array_replace. using array_merge for 5.2 BC
215  $query = array_merge($qs, $query);
216  }
217  $queryString = http_build_query($query, '', '&');
218 
219  $server['REQUEST_URI'] = $components['path'] . ('' !== $queryString ? '?' . $queryString : '');
220  $server['QUERY_STRING'] = $queryString;
221 
222  return new \Elgg\Http\Request($query, $request, $cookies, $files, $server);
223  }
224 
235  public static function normalizeQueryString($qs) {
236  if ('' == $qs) {
237  return '';
238  }
239 
240  $parts = array();
241  $order = array();
242 
243  foreach (explode('&', $qs) as $param) {
244  if ('' === $param || '=' === $param[0]) {
245  // Ignore useless delimiters, e.g. "x=y&".
246  // Also ignore pairs with empty key, even if there was a value, e.g. "=value",
247  // as such nameless values cannot be retrieved anyway.
248  // PHP also does not include them when building _GET.
249  continue;
250  }
251 
252  $keyValuePair = explode('=', $param, 2);
253 
254  // GET parameters, that are submitted from a HTML form,
255  // encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
256  // PHP also converts "+" to spaces when filling the global _GET or
257  // when using the function parse_str. This is why we use urldecode and then normalize to
258  // RFC 3986 with rawurlencode.
259  $parts[] = isset($keyValuePair[1]) ?
260  rawurlencode(urldecode($keyValuePair[0])) . '=' . rawurlencode(urldecode($keyValuePair[1])) :
261  rawurlencode(urldecode($keyValuePair[0]));
262  $order[] = urldecode($keyValuePair[0]);
263  }
264 
265  array_multisort($order, SORT_ASC, $parts);
266 
267  return implode('&', $parts);
268  }
269 
280  public function get($key, $default = null) {
281  if ($this->query->has($key)) {
282  return $this->query->get($key);
283  } else if ($this->request->has($key)) {
284  return $this->request->get($key);
285  } else {
286  return $default;
287  }
288  }
289 
295  public function getRequestUri() {
296  if (null === $this->requestUri) {
297  $this->requestUri = $this->prepareRequestUri();
298  }
299 
300  return $this->requestUri;
301  }
302 
308  public function getUri() {
309  if (null !== $qs = $this->getQueryString()) {
310  $qs = '?' . $qs;
311  }
312 
313  return $this->getSchemeAndHttpHost() . $this->getBaseUrl() . $this->getPathInfo() . $qs;
314  }
315 
323  public function getSchemeAndHttpHost() {
324  return $this->getScheme() . '://' . $this->getHttpHost();
325  }
326 
332  public function getScheme() {
333  return $this->isSecure() ? 'https' : 'http';
334  }
335 
343  public function getHttpHost() {
344  $scheme = $this->getScheme();
345  $port = $this->getPort();
346 
347  if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) {
348  return $this->getHost();
349  }
350 
351  return $this->getHost() . ':' . $port;
352  }
353 
361  public function getHost() {
362  if (!$host = $this->headers->get('HOST')) {
363  if (!$host = $this->server->get('SERVER_NAME')) {
364  $host = $this->server->get('SERVER_ADDR', '');
365  }
366  }
367 
368  // trim and remove port number from host
369  // host is lowercase as per RFC 952/2181
370  $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
371 
372  // as the host can come from the user (HTTP_HOST and depending on the configuration,
373  // SERVER_NAME too can come from the user)
374  // check that it does not contain forbidden characters (see RFC 952 and RFC 2181)
375  if ($host && !preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host)) {
376  throw new \UnexpectedValueException('Invalid Host');
377  }
378 
379  return $host;
380  }
381 
387  public function isSecure() {
388  return 'on' == strtolower($this->server->get('HTTPS')) || 1 == $this->server->get('HTTPS');
389  }
390 
396  public function getPort() {
397  return $this->server->get('SERVER_PORT');
398  }
399 
413  public function getBaseUrl() {
414  if (null === $this->baseUrl) {
415  $this->baseUrl = $this->prepareBaseUrl();
416  }
417 
418  return $this->baseUrl;
419  }
420 
436  public function getPathInfo() {
437  if (null === $this->pathInfo) {
438  $this->pathInfo = $this->preparePathInfo();
439  }
440 
441  return $this->pathInfo;
442  }
443 
452  public function getQueryString() {
453  $qs = \Elgg\Http\Request::normalizeQueryString($this->server->get('QUERY_STRING'));
454 
455  return '' === $qs ? null : $qs;
456  }
457 
465  public function getUrlSegments() {
466  $path = trim($this->query->get('__elgg_uri'), '/');
467  if (!$path) {
468  return array();
469  }
470 
471  return explode('/', $path);
472  }
473 
481  public function getFirstUrlSegment() {
482  $segments = $this->getUrlSegments();
483  if ($segments) {
484  return array_shift($segments);
485  } else {
486  return '';
487  }
488  }
489 
495  public function getClientIp() {
497 
498  $ip_address = $server->get('HTTP_X_FORWARDED_FOR');
499  if (!empty($ip_address)) {
500  return array_pop(explode(',', $ip_address));
501  }
502 
503  $ip_address = $server->get('HTTP_X_REAL_IP');
504  if (!empty($ip_address)) {
505  return array_pop(explode(',', $ip_address));
506  }
507 
508  return $server->get('REMOTE_ADDR');
509  }
510 
516  public function isXmlHttpRequest() {
517  return $this->headers->get('X-Requested-With') == 'XMLHttpRequest' ||
518  $this->get('X-Requested-With') === 'XMLHttpRequest';
519  }
520 
527  protected function stripSlashesIfMagicQuotes($data) {
528  if (get_magic_quotes_gpc()) {
530  } else {
531  return $data;
532  }
533  }
534 
540  protected function prepareHeaders() {
541  $headers = array();
542  $contentHeaders = array('CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true);
543  foreach ($this->server as $key => $value) {
544  if (0 === strpos($key, 'HTTP_')) {
545  $key = strtr(strtolower(substr($key, 5)), '_', '-');
546  $key = implode('-', array_map('ucfirst', explode('-', $key)));
547  $headers[$key] = $value;
548  } elseif (isset($contentHeaders[$key])) {
549  $key = strtr(strtolower($key), '_', '-');
550  $key = implode('-', array_map('ucfirst', explode('-', $key)));
551  $headers[$key] = $value;
552  }
553  }
554 
555  return $headers;
556  }
557 
566  protected function prepareRequestUri() {
567  return $this->server->get('REQUEST_URI');
568  }
569 
575  protected function prepareBaseUrl() {
576  $filename = basename($this->server->get('SCRIPT_FILENAME'));
577 
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 
601  // Does the baseUrl have anything in common with the request_uri?
602  $requestUri = $this->getRequestUri();
603 
604  if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
605  // full $baseUrl matches
606  return $prefix;
607  }
608 
609  if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, dirname($baseUrl))) {
610  // directory portion of $baseUrl matches
611  return rtrim($prefix, '/');
612  }
613 
614  $truncatedRequestUri = $requestUri;
615  if (($pos = strpos($requestUri, '?')) !== false) {
616  $truncatedRequestUri = substr($requestUri, 0, $pos);
617  }
618 
619  $basename = basename($baseUrl);
620  if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
621  // no match whatsoever; set it blank
622  return '';
623  }
624 
625  // If using mod_rewrite or ISAPI_Rewrite strip the script filename
626  // out of baseUrl. $pos !== 0 makes sure it is not matching a value
627  // from PATH_INFO or QUERY_STRING
628  if ((strlen($requestUri) >= strlen($baseUrl)) && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) {
629  $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
630  }
631 
632  return rtrim($baseUrl, '/');
633  }
634 
640  protected function preparePathInfo() {
641  $baseUrl = $this->getBaseUrl();
642 
643  if (null === ($requestUri = $this->getRequestUri())) {
644  return '/';
645  }
646 
647  $pathInfo = '/';
648 
649  // Remove the query string from REQUEST_URI
650  if ($pos = strpos($requestUri, '?')) {
651  $requestUri = substr($requestUri, 0, $pos);
652  }
653 
654  if ((null !== $baseUrl) && (false === ($pathInfo = substr($requestUri, strlen($baseUrl))))) {
655  // If substr() returns false then PATH_INFO is set to an empty string
656  return '/';
657  } elseif (null === $baseUrl) {
658  return $requestUri;
659  }
660 
661  return (string) $pathInfo;
662  }
663 
673  private function getUrlencodedPrefix($string, $prefix) {
674  if (0 !== strpos(rawurldecode($string), $prefix)) {
675  return false;
676  }
677 
678  $len = strlen($prefix);
679 
680  if (preg_match("#^(%[[:xdigit:]]{2}|.){{$len}}#", $string, $match)) {
681  return $match[0];
682  }
683 
684  return false;
685  }
686 
687 }
688 
$filename
Definition: crop.php:23
getClientIp()
Get the IP address of the client.
Definition: Request.php:495
getPathInfo()
Returns the path being requested relative to the executed script.
Definition: Request.php:436
getRequestUri()
Returns the requested URI.
Definition: Request.php:295
stripSlashesIfMagicQuotes($data)
Strip slashes if magic quotes is on.
Definition: Request.php:527
getHttpHost()
Returns the HTTP host being requested.
Definition: Request.php:343
isXmlHttpRequest()
Is this an ajax request.
Definition: Request.php:516
getPort()
Returns the port on which the request is made.
Definition: Request.php:396
initialize(array $query=array(), array $request=array(), array $cookies=array(), array $files=array(), array $server=array())
Initialize the request.
Definition: Request.php:113
prepareRequestUri()
Set the request URI.
Definition: Request.php:566
isSecure()
Is this request using SSL.
Definition: Request.php:387
static normalizeQueryString($qs)
Normalizes a query string.
Definition: Request.php:235
prepareHeaders()
Get the HTTP headers from server.
Definition: Request.php:540
getBaseUrl()
Returns the root url from which this request is executed.
Definition: Request.php:413
static createFromGlobals()
Creates a request from PHP's globals.
Definition: Request.php:132
getQueryString()
Gets the normalized query string for the Request.
Definition: Request.php:452
static create($uri, $method='GET', $parameters=array(), $cookies=array(), $files=array(), $server=array())
Creates a Request based on a given URI and configuration.
Definition: Request.php:151
getSchemeAndHttpHost()
Gets the scheme and HTTP host.
Definition: Request.php:323
getFirstUrlSegment()
Get first URL segment from the path info.
Definition: Request.php:481
getUri()
Generates a normalized URI for the Request.
Definition: Request.php:308
getScheme()
Gets the request's scheme.
Definition: Request.php:332
__construct(array $query=array(), array $request=array(), array $cookies=array(), array $files=array(), array $server=array())
Create a request.
Definition: Request.php:98
getUrlSegments()
Get URL segments from the path info.
Definition: Request.php:465
preparePathInfo()
Prepares the path info.
Definition: Request.php:640
prepareBaseUrl()
Prepares the base URL.
Definition: Request.php:575
getHost()
Returns the host name.
Definition: Request.php:361
$default
Definition: checkbox.php:36
$value
Definition: longtext.php:29
_elgg_stripslashes_deep($value)
Strip slashes.
Definition: input.php:428
$method
Definition: form.php:25
$path
Definition: invalid.php:17
$data
Definition: opendd.php:13
$key
Definition: summary.php:34
$string