SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/Request.php

Copyright (C) 2017 Karmabunny Pty Ltd.

This file is a part of SproutCMS.

SproutCMS is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation, either
version 2 of the License, or (at your option) any later version.

For more information, visit <http://getsproutcms.com>.

This class was originally from Kohana 2.3.4
Copyright 2007-2008 Kohana Team
  1. <?php
  2. /**
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  *
  13.  * This class was originally from Kohana 2.3.4
  14.  * Copyright 2007-2008 Kohana Team
  15.  */
  16. namespace Sprout\Helpers;
  17.  
  18. use Kohana;
  19. use Kohana_Exception;
  20.  
  21.  
  22. /**
  23.  * Get information about the incoming HTTP request.
  24.  */
  25. class Request
  26. {
  27.  
  28. // Possible HTTP methods
  29. protected static $http_methods = array('get', 'head', 'options', 'post', 'put', 'delete');
  30.  
  31. // Content types from client's HTTP Accept request header (array)
  32. protected static $accept_types;
  33.  
  34.  
  35. /**
  36.   * Returns the HTTP referrer, or the default if the referrer is not set.
  37.   *
  38.   * @param mixed default to return
  39.   * @return string
  40.   */
  41. public static function referrer($default = FALSE)
  42. {
  43. if ( ! empty($_SERVER['HTTP_REFERER']))
  44. {
  45. // Set referrer
  46. $ref = $_SERVER['HTTP_REFERER'];
  47.  
  48. if (strpos($ref, Url::base(FALSE)) === 0)
  49. {
  50. // Remove the base URL from the referrer
  51. $ref = substr($ref, strlen(Url::base(FALSE)));
  52. }
  53. }
  54.  
  55. return isset($ref) ? $ref : $default;
  56. }
  57.  
  58. /**
  59.   * Returns the current request protocol, based on $_SERVER['https']. In CLI
  60.   * mode, NULL will be returned.
  61.   *
  62.   * @return string
  63.   */
  64. public static function protocol()
  65. {
  66. if (!empty($_SERVER['PHP_S_PROTOCOL'])) {
  67. return $_SERVER['PHP_S_PROTOCOL'];
  68. } elseif (PHP_SAPI === 'cli') {
  69. return NULL;
  70. } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) and Kohana::config('sprout.load_balanced')) {
  71. return $_SERVER['HTTP_X_FORWARDED_PROTO'];
  72. } elseif (!empty($_SERVER['HTTPS']) AND $_SERVER['HTTPS'] === 'on') {
  73. return 'https';
  74. } else {
  75. return 'http';
  76. }
  77. }
  78.  
  79. /**
  80.   * Tests if the current request is an AJAX request by checking the X-Requested-With HTTP
  81.   * request header that most popular JS frameworks now set for AJAX calls.
  82.   *
  83.   * @return boolean
  84.   */
  85. public static function isAjax()
  86. {
  87. return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
  88. }
  89.  
  90. /**
  91.   * Returns current request method.
  92.   *
  93.   * @throws Kohana_Exception in case of an unknown request method
  94.   * @return string
  95.   */
  96. public static function method()
  97. {
  98. $method = strtolower($_SERVER['REQUEST_METHOD']);
  99.  
  100. if ( ! in_array($method, Request::$http_methods))
  101. throw new Kohana_Exception('request.unknown_method', $method);
  102.  
  103. return $method;
  104. }
  105.  
  106.  
  107. /**
  108.   * Returns the users IP address, accounting for proxy forwarding
  109.   */
  110. public static function userIp()
  111. {
  112. if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) and Kohana::config('sprout.load_balanced'))
  113. {
  114. $parts = explode(', ', $_SERVER['HTTP_X_FORWARDED_FOR']);
  115. return $parts[0];
  116. }
  117. else if (!empty($_SERVER['REMOTE_ADDR']))
  118. {
  119. return $_SERVER['REMOTE_ADDR'];
  120. }
  121. else
  122. {
  123. return '0.0.0.0';
  124. }
  125. }
  126.  
  127. /**
  128.   * Returns boolean of whether client accepts content type.
  129.   *
  130.   * @param string content type
  131.   * @param boolean set to TRUE to disable wildcard checking
  132.   * @return boolean
  133.   */
  134. public static function accepts($type = NULL, $explicit_check = FALSE)
  135. {
  136. Request::parseAcceptHeader();
  137.  
  138. if ($type === NULL)
  139. return Request::$accept_types;
  140.  
  141. return (Request::acceptsAtQuality($type, $explicit_check) > 0);
  142. }
  143.  
  144. /**
  145.   * Compare the q values for given array of content types and return the one with the highest value.
  146.   * If items are found to have the same q value, the first one encountered in the given array wins.
  147.   * If all items in the given array have a q value of 0, FALSE is returned.
  148.   *
  149.   * @param array content types
  150.   * @param boolean set to TRUE to disable wildcard checking
  151.   * @return mixed string mime type with highest q value, FALSE if none of the given types are accepted
  152.   */
  153. public static function preferredAccept($types, $explicit_check = FALSE)
  154. {
  155. // Initialize
  156. $mime_types = array();
  157. $max_q = 0;
  158. $preferred = FALSE;
  159.  
  160. // Load q values for all given content types
  161. foreach (array_unique($types) as $type)
  162. {
  163. $mime_types[$type] = Request::acceptsAtQuality($type, $explicit_check);
  164. }
  165.  
  166. // Look for the highest q value
  167. foreach ($mime_types as $type => $q)
  168. {
  169. if ($q > $max_q)
  170. {
  171. $max_q = $q;
  172. $preferred = $type;
  173. }
  174. }
  175.  
  176. return $preferred;
  177. }
  178.  
  179. /**
  180.   * Returns quality factor at which the client accepts content type.
  181.   *
  182.   * @param string content type (e.g. "image/jpg", "jpg")
  183.   * @param boolean set to TRUE to disable wildcard checking
  184.   * @return integer|float
  185.   */
  186. public static function acceptsAtQuality($type = NULL, $explicit_check = FALSE)
  187. {
  188. Request::parseAcceptHeader();
  189.  
  190. // Normalize type
  191. $type = strtolower((string) $type);
  192.  
  193. // General content type (e.g. "jpg")
  194. if (strpos($type, '/') === FALSE)
  195. {
  196. // Don't accept anything by default
  197. $q = 0;
  198.  
  199. // Look up relevant mime types
  200. foreach ((array) Kohana::config('mimes.'.$type) as $type)
  201. {
  202. $q2 = Request::acceptsAtQuality($type, $explicit_check);
  203. $q = ($q2 > $q) ? $q2 : $q;
  204. }
  205.  
  206. return $q;
  207. }
  208.  
  209. // Content type with subtype given (e.g. "image/jpg")
  210. $type = explode('/', $type, 2);
  211.  
  212. // Exact match
  213. if (isset(Request::$accept_types[$type[0]][$type[1]]))
  214. return Request::$accept_types[$type[0]][$type[1]];
  215.  
  216. // Wildcard match (if not checking explicitly)
  217. if ($explicit_check === FALSE AND isset(Request::$accept_types[$type[0]]['*']))
  218. return Request::$accept_types[$type[0]]['*'];
  219.  
  220. // Catch-all wildcard match (if not checking explicitly)
  221. if ($explicit_check === FALSE AND isset(Request::$accept_types['*']['*']))
  222. return Request::$accept_types['*']['*'];
  223.  
  224. // Content type not accepted
  225. return 0;
  226. }
  227.  
  228. /**
  229.   * Parses client's HTTP Accept request header, and builds array structure representing it.
  230.   *
  231.   * @return void
  232.   */
  233. protected static function parseAcceptHeader()
  234. {
  235. // Run this function just once
  236. if (Request::$accept_types !== NULL)
  237. return;
  238.  
  239. // Initialize accept_types array
  240. Request::$accept_types = array();
  241.  
  242. // No HTTP Accept header found
  243. if (empty($_SERVER['HTTP_ACCEPT']))
  244. {
  245. // Accept everything
  246. Request::$accept_types['*']['*'] = 1;
  247. return;
  248. }
  249.  
  250. // Remove linebreaks and parse the HTTP Accept header
  251. foreach (explode(',', str_replace(array("\r", "\n"), '', $_SERVER['HTTP_ACCEPT'])) as $accept_entry)
  252. {
  253. // Explode each entry in content type and possible quality factor
  254. $accept_entry = explode(';', trim($accept_entry), 2);
  255.  
  256. // Explode each content type (e.g. "text/html")
  257. $type = explode('/', $accept_entry[0], 2);
  258.  
  259. // Skip invalid content types
  260. if ( ! isset($type[1]))
  261. continue;
  262.  
  263. // Assume a default quality factor of 1 if no custom q value found
  264. $q = (isset($accept_entry[1]) AND preg_match('~\bq\s*+=\s*+([.0-9]+)~', $accept_entry[1], $match)) ? (float) $match[1] : 1;
  265.  
  266. // Populate accept_types array
  267. if ( ! isset(Request::$accept_types[$type[0]][$type[1]]) OR $q > Request::$accept_types[$type[0]][$type[1]])
  268. {
  269. Request::$accept_types[$type[0]][$type[1]] = $q;
  270. }
  271. }
  272. }
  273.  
  274.  
  275. /**
  276.   * Get the headers as an array.
  277.   *
  278.   * All keys are lowercase.
  279.   *
  280.   * @return array [ name => value ]
  281.   */
  282. public static function getHeaders()
  283. {
  284. static $headers;
  285. if ($headers !== null) return $headers;
  286.  
  287. $headers = [];
  288.  
  289. foreach ($_SERVER as $key => $value) {
  290. $key = strtolower($key);
  291.  
  292. if (strpos($key, 'http_') === 0) {
  293. $key = str_replace('_', '-', substr($key, 5));
  294. }
  295. else if (strpos($key, 'content_') === 0) {
  296. $key = str_replace('_', '-', $key);
  297. }
  298. else {
  299. continue;
  300. }
  301.  
  302. $headers[$key] = $value;
  303. }
  304.  
  305. return $headers;
  306. }
  307.  
  308.  
  309. } // End request
  310.