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 
$method
Definition: form.php:25
elgg parse_str
Returns an object with key/values of the parsed query string.
Definition: elgglib.js:505
__construct(array $query=array(), array $request=array(), array $cookies=array(), array $files=array(), array $server=array())
Create a request.
Definition: Request.php:98
getHost()
Returns the host name.
Definition: Request.php:361
getFirstUrlSegment()
Get first URL segment from the path info.
Definition: Request.php:481
preparePathInfo()
Prepares the path info.
Definition: Request.php:640
$data
Definition: opendd.php:13
$value
Definition: longtext.php:29
$default
Definition: checkbox.php:36
getClientIp()
Get the IP address of the client.
Definition: Request.php:495
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
elgg parse_url
Parse a URL into its parts.
Definition: elgglib.js:432
getScheme()
Gets the request&#39;s scheme.
Definition: Request.php:332
prepareBaseUrl()
Prepares the base URL.
Definition: Request.php:575
$string
isXmlHttpRequest()
Is this an ajax request.
Definition: Request.php:516
initialize(array $query=array(), array $request=array(), array $cookies=array(), array $files=array(), array $server=array())
Initialize the request.
Definition: Request.php:113
getSchemeAndHttpHost()
Gets the scheme and HTTP host.
Definition: Request.php:323
stripSlashesIfMagicQuotes($data)
Strip slashes if magic quotes is on.
Definition: Request.php:527
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition files
Definition: LICENSE.txt:157
$key
Definition: summary.php:34
getUri()
Generates a normalized URI for the Request.
Definition: Request.php:308
getQueryString()
Gets the normalized query string for the Request.
Definition: Request.php:452
getRequestUri()
Returns the requested URI.
Definition: Request.php:295
isSecure()
Is this request using SSL.
Definition: Request.php:387
getUrlSegments()
Get URL segments from the path info.
Definition: Request.php:465
getPort()
Returns the port on which the request is made.
Definition: Request.php:396
_elgg_stripslashes_deep($value)
Strip slashes.
Definition: input.php:428
getPathInfo()
Returns the path being requested relative to the executed script.
Definition: Request.php:436
$filename
Definition: crop.php:23
getBaseUrl()
Returns the root url from which this request is executed.
Definition: Request.php:413
getHttpHost()
Returns the HTTP host being requested.
Definition: Request.php:343
$path
Definition: invalid.php:17
prepareHeaders()
Get the HTTP headers from server.
Definition: Request.php:540
static normalizeQueryString($qs)
Normalizes a query string.
Definition: Request.php:235
static createFromGlobals()
Creates a request from PHP&#39;s globals.
Definition: Request.php:132
prepareRequestUri()
Set the request URI.
Definition: Request.php:566