PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/symphony/lib/toolkit/class.page.php

http://github.com/symphonycms/symphony-2
PHP | 367 lines | 123 code | 31 blank | 213 comment | 18 complexity | bab956598c3e6f577889f41198378241 MD5 | raw file
  1. <?php
  2. /**
  3. * @package toolkit
  4. */
  5. /**
  6. * Page is an abstract class that holds an object representation
  7. * of a page's headers.
  8. */
  9. abstract class Page
  10. {
  11. /**
  12. * Refers to the HTTP status code, 200 OK
  13. *
  14. * @since Symphony 2.3.2
  15. * @var integer
  16. */
  17. const HTTP_STATUS_OK = 200;
  18. /**
  19. * Refers to the HTTP status code, 301 Moved Permanently
  20. *
  21. * @since Symphony 2.3.2
  22. * @var integer
  23. */
  24. const HTTP_STATUS_MOVED_PERMANENT = 301;
  25. /**
  26. * Refers to the HTTP status code, 302 Found
  27. * This is used as a temporary redirect
  28. *
  29. * @since Symphony 2.3.2
  30. * @var integer
  31. */
  32. const HTTP_STATUS_FOUND = 302;
  33. /**
  34. * Refers to the HTTP status code, 304 Not Modified
  35. *
  36. * @since Symphony 2.3.2
  37. * @var integer
  38. */
  39. const HTTP_NOT_MODIFIED = 304;
  40. /**
  41. * Refers to the HTTP status code, 400 Bad Request
  42. *
  43. * @since Symphony 2.3.2
  44. * @var integer
  45. */
  46. const HTTP_STATUS_BAD_REQUEST = 400;
  47. /**
  48. * Refers to the HTTP status code, 401 Unauthorized
  49. *
  50. * @since Symphony 2.3.2
  51. * @var integer
  52. */
  53. const HTTP_STATUS_UNAUTHORIZED = 401;
  54. /**
  55. * Refers to the HTTP status code, 403 Forbidden
  56. *
  57. * @since Symphony 2.3.2
  58. * @var integer
  59. */
  60. const HTTP_STATUS_FORBIDDEN = 403;
  61. /**
  62. * Refers to the HTTP status code, 404 Not Found
  63. *
  64. * @since Symphony 2.3.2
  65. * @var integer
  66. */
  67. const HTTP_STATUS_NOT_FOUND = 404;
  68. /**
  69. * Refers to the HTTP status code, 500 Internal Server Error
  70. *
  71. * @since Symphony 2.3.2
  72. * @var integer
  73. */
  74. const HTTP_STATUS_ERROR = 500;
  75. /**
  76. * Keyed array of all the string
  77. *
  78. * @since Symphony 2.3.2
  79. * @var array
  80. */
  81. public static $HTTP_STATUSES = array(
  82. // 200
  83. self::HTTP_STATUS_OK => 'OK',
  84. // 300
  85. self::HTTP_STATUS_MOVED_PERMANENT => 'Moved Permanently',
  86. self::HTTP_STATUS_FOUND => 'Found',
  87. self::HTTP_NOT_MODIFIED => 'Not Modified',
  88. // 400
  89. self::HTTP_STATUS_BAD_REQUEST => 'Bad Request',
  90. self::HTTP_STATUS_UNAUTHORIZED => 'Unauthorized',
  91. self::HTTP_STATUS_FORBIDDEN => 'Forbidden',
  92. self::HTTP_STATUS_NOT_FOUND => 'Not Found',
  93. // 500
  94. self::HTTP_STATUS_ERROR => 'Internal Server Error',
  95. );
  96. /**
  97. * This stores the headers that will be sent when this page is
  98. * generated as an associative array of header=>value.
  99. *
  100. * @var array
  101. */
  102. protected $_headers = array();
  103. /**
  104. * An associative array describing this pages context. This
  105. * can include the section handle, the current entry_id, the page
  106. * name and any flags such as 'saved' or 'created'. This variable
  107. * often provided in delegates so extensions can manipulate based
  108. * off the current context or add new keys.
  109. * @var array
  110. */
  111. protected $_context = [];
  112. /**
  113. * Initialises the Page object by setting the headers to empty
  114. */
  115. public function __construct()
  116. {
  117. $this->_headers = array();
  118. }
  119. /**
  120. *
  121. * This method returns the string HTTP Status value.
  122. * If `$status_code` is null, it returns all the values
  123. * currently registered.
  124. *
  125. * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  126. *
  127. * @since Symphony 2.3.2
  128. *
  129. * @param integer $status_code (optional)
  130. * The HTTP Status code to get the value for.
  131. * @return array|string
  132. * Returns string if the $status_code is not null. Array otherwise
  133. */
  134. final public static function getHttpStatusValue($status_code = null)
  135. {
  136. if (!$status_code) {
  137. return self::$HTTP_STATUSES;
  138. }
  139. return self::$HTTP_STATUSES[$status_code];
  140. }
  141. /**
  142. * This method format the provided `$status_code` to used
  143. * php's `header()` function.
  144. *
  145. * @since Symphony 2.3.2
  146. *
  147. * @param integer $status_code
  148. * The HTTP Status code to get the value for
  149. * @return string
  150. * The formatted HTTP Status string
  151. */
  152. final public static function getHeaderStatusString($status_code)
  153. {
  154. return sprintf("Status: %d %s", $status_code, self::getHttpStatusValue($status_code));
  155. }
  156. /**
  157. * Sets the `$sting_value` for the specified `$status_code`.
  158. * If `$sting_value` is null, the `$status_code` is removed from
  159. * the array.
  160. *
  161. * This allow developers to register customs HTTP_STATUS into the
  162. * static `Page::$HTTP_STATUSES` array and use `$page->setHttpStatus()`.
  163. *
  164. * @since Symphony 2.3.2
  165. *
  166. * @param integer $status_code
  167. * The HTTP Status numeric code.
  168. * @param string $string_value
  169. * The HTTP Status string value.
  170. */
  171. final public static function setHttpStatusValue($status_code, $string_value)
  172. {
  173. if (!$string_value) {
  174. unset(self::$HTTP_STATUSES[$status_code]);
  175. } elseif (is_int($status_code) && $status_code >= 100 && $status_code < 600) {
  176. self::$HTTP_STATUSES[$status_code] = $string_value;
  177. } else {
  178. // Throw error ?
  179. }
  180. }
  181. /**
  182. * Adds a header to the $_headers array using the $name
  183. * as the key.
  184. *
  185. * @param string $name
  186. * The header name, eg. Content-Type.
  187. * @param string $value (optional)
  188. * The value for the header, eg. text/xml. Defaults to null.
  189. * @param integer $response_code (optional)
  190. * The HTTP response code that should be set by PHP with this header, eg. 200
  191. */
  192. public function addHeaderToPage($name, $value = null, $response_code = null)
  193. {
  194. $this->_headers[strtolower($name)] = array(
  195. 'header' => $name . (is_null($value) ? null : ":{$value}"),
  196. 'response_code' => $response_code
  197. );
  198. }
  199. /**
  200. * Removes a header from the $_headers array using the $name
  201. * as the key.
  202. *
  203. * @param string $name
  204. * The header name, eg. Expires.
  205. */
  206. public function removeHeaderFromPage($name)
  207. {
  208. unset($this->_headers[strtolower($name)]);
  209. }
  210. /**
  211. * Shorthand for `addHeaderToPage` in order to set the
  212. * HTTP Status header.
  213. *
  214. * @since Symphony 2.3.2
  215. *
  216. * @param integer $status_code
  217. * The HTTP Status numeric value.
  218. */
  219. public function setHttpStatus($status_code)
  220. {
  221. $this->addHeaderToPage('Status', null, $status_code);
  222. }
  223. /**
  224. * Gets the current HTTP Status.
  225. * If none is set, it assumes HTTP_STATUS_OK
  226. *
  227. * @since Symphony 2.3.2
  228. *
  229. * @return integer
  230. */
  231. public function getHttpStatusCode()
  232. {
  233. if (isset($this->_headers['status'])) {
  234. return $this->_headers['status']['response_code'];
  235. }
  236. return self::HTTP_STATUS_OK;
  237. }
  238. /**
  239. * Accessor function for `$_headers`
  240. *
  241. * @return array
  242. */
  243. public function headers()
  244. {
  245. return $this->_headers;
  246. }
  247. /**
  248. * This function prepares any data needed for generation.
  249. * The default implementation simply captures the $context variable.
  250. * into the object's $_context property.
  251. *
  252. * @param array $context
  253. * An associative array describing this pages context.
  254. * @return void
  255. */
  256. public function build(array $context = [])
  257. {
  258. $this->_context = $context;
  259. }
  260. /**
  261. * This function should generate the content to send to the client.
  262. * The base implementation returns an empty body.
  263. * This function calls `renderHeaders()`.
  264. *
  265. * @see renderHeaders()
  266. * @return string
  267. */
  268. public function generate($page = null)
  269. {
  270. $this->renderHeaders();
  271. return '';
  272. }
  273. /**
  274. * This method calls php's `header()` function
  275. * in order to set the HTTP status code properly on all platforms.
  276. *
  277. * @see https://github.com/symphonycms/symphonycms/issues/1558#issuecomment-10663716
  278. *
  279. * @param integer $status_code
  280. */
  281. final public static function renderStatusCode($status_code)
  282. {
  283. header(self::getHeaderStatusString($status_code), true, $status_code);
  284. }
  285. /**
  286. * Iterates over the `$_headers` for this page and outputs them using PHP's
  287. * header() function. Since Symphony 3.0.0, this will add additional Pragma
  288. * and Expires headers when the request is made over HTTP 1.0 and we are
  289. * sending a Cache-Control header
  290. */
  291. protected function renderHeaders()
  292. {
  293. // When the request was made using HTTP 1.0 and the Cache Control header
  294. // was set to 'no-cache', add the Pragma and Expires headers. RE: #2205.
  295. // Thanks to Symfony HttpFoundation for the idea as well.
  296. if (strpos(server_safe('SERVER_PROTOCOL'), 'HTTP/1.0') !== false) {
  297. if (
  298. isset($this->_headers['cache-control']['header'])
  299. && strpos($this->_headers['cache-control']['header'], 'no-cache') !== false
  300. ) {
  301. $this->addHeaderToPage('Pragma', 'no-cache');
  302. $this->addHeaderToPage('Expires', 'Mon, 12 Dec 1982 06:14:00 GMT');
  303. }
  304. }
  305. if (!is_array($this->_headers) || empty($this->_headers)) {
  306. return;
  307. }
  308. foreach ($this->_headers as $key => $value) {
  309. // If this is the http status
  310. if ($key == 'status' && isset($value['response_code'])) {
  311. $res_code = intval($value['response_code']);
  312. self::renderStatusCode($res_code);
  313. } else {
  314. header($value['header']);
  315. }
  316. }
  317. }
  318. /**
  319. * This function will check to ensure that this post request is not larger than
  320. * what the server is set to handle. If it is, a notice is shown.
  321. *
  322. * @link https://github.com/symphonycms/symphonycms/issues/1187
  323. * @since Symphony 2.5.2
  324. */
  325. public function isRequestValid()
  326. {
  327. $max_size = @ini_get('post_max_size');
  328. if (!$max_size) {
  329. return true;
  330. }
  331. if (server_safe('REQUEST_METHOD') === 'POST' && (int)server_safe('CONTENT_LENGTH') > General::convertHumanFileSizeToBytes($max_size)) {
  332. return false;
  333. }
  334. return true;
  335. }
  336. }