PageRenderTime 72ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/www/libs/nette-dev/Web/HttpResponse.php

https://github.com/bazo/Mokuji
PHP | 353 lines | 170 code | 67 blank | 116 comment | 24 complexity | c8d3d5672ceedeb11aaa0f86fbefe252 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Web
  10. */
  11. /**
  12. * HttpResponse class.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette\Web
  16. *
  17. * @property int $code
  18. * @property-read array $headers
  19. * @property-read mixed $sent
  20. */
  21. final class HttpResponse extends Object implements IHttpResponse
  22. {
  23. /** @var bool Send invisible garbage for IE 6? */
  24. private static $fixIE = TRUE;
  25. /** @var string The domain in which the cookie will be available */
  26. public $cookieDomain = '';
  27. /** @var string The path in which the cookie will be available */
  28. public $cookiePath = '/';
  29. /** @var string The path in which the cookie will be available */
  30. public $cookieSecure = FALSE;
  31. /** @var int HTTP response code */
  32. private $code = self::S200_OK;
  33. /**
  34. * Sets HTTP response code.
  35. * @param int
  36. * @return HttpResponse provides a fluent interface
  37. * @throws InvalidArgumentException if code is invalid
  38. * @throws InvalidStateException if HTTP headers have been sent
  39. */
  40. public function setCode($code)
  41. {
  42. $code = (int) $code;
  43. static $allowed = array(
  44. 200=>1, 201=>1, 202=>1, 203=>1, 204=>1, 205=>1, 206=>1,
  45. 300=>1, 301=>1, 302=>1, 303=>1, 304=>1, 307=>1,
  46. 400=>1, 401=>1, 403=>1, 404=>1, 406=>1, 408=>1, 410=>1, 412=>1, 415=>1, 416=>1,
  47. 500=>1, 501=>1, 503=>1, 505=>1
  48. );
  49. if (!isset($allowed[$code])) {
  50. throw new InvalidArgumentException("Bad HTTP response '$code'.");
  51. } elseif (headers_sent($file, $line)) {
  52. throw new InvalidStateException("Cannot set HTTP code after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
  53. } else {
  54. $this->code = $code;
  55. $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
  56. header($protocol . ' ' . $code, TRUE, $code);
  57. }
  58. return $this;
  59. }
  60. /**
  61. * Returns HTTP response code.
  62. * @return int
  63. */
  64. public function getCode()
  65. {
  66. return $this->code;
  67. }
  68. /**
  69. * Sends a HTTP header and replaces a previous one.
  70. * @param string header name
  71. * @param string header value
  72. * @return HttpResponse provides a fluent interface
  73. * @throws InvalidStateException if HTTP headers have been sent
  74. */
  75. public function setHeader($name, $value)
  76. {
  77. if (headers_sent($file, $line)) {
  78. throw new InvalidStateException("Cannot send header after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
  79. }
  80. if ($value === NULL && function_exists('header_remove')) {
  81. header_remove($name);
  82. } else {
  83. header($name . ': ' . $value, TRUE, $this->code);
  84. }
  85. return $this;
  86. }
  87. /**
  88. * Adds HTTP header.
  89. * @param string header name
  90. * @param string header value
  91. * @return void
  92. * @throws InvalidStateException if HTTP headers have been sent
  93. */
  94. public function addHeader($name, $value)
  95. {
  96. if (headers_sent($file, $line)) {
  97. throw new InvalidStateException("Cannot send header after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
  98. }
  99. header($name . ': ' . $value, FALSE, $this->code);
  100. }
  101. /**
  102. * Sends a Content-type HTTP header.
  103. * @param string mime-type
  104. * @param string charset
  105. * @return HttpResponse provides a fluent interface
  106. * @throws InvalidStateException if HTTP headers have been sent
  107. */
  108. public function setContentType($type, $charset = NULL)
  109. {
  110. $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
  111. return $this;
  112. }
  113. /**
  114. * Redirects to a new URL. Note: call exit() after it.
  115. * @param string URL
  116. * @param int HTTP code
  117. * @return void
  118. * @throws InvalidStateException if HTTP headers have been sent
  119. */
  120. public function redirect($url, $code = self::S302_FOUND)
  121. {
  122. if (isset($_SERVER['SERVER_SOFTWARE']) && preg_match('#^Microsoft-IIS/[1-5]#', $_SERVER['SERVER_SOFTWARE']) && $this->getHeader('Set-Cookie') !== NULL) {
  123. $this->setHeader('Refresh', "0;url=$url");
  124. return;
  125. }
  126. $this->setCode($code);
  127. $this->setHeader('Location', $url);
  128. echo "<h1>Redirect</h1>\n\n<p><a href=\"" . htmlSpecialChars($url) . "\">Please click here to continue</a>.</p>";
  129. }
  130. /**
  131. * Sets the number of seconds before a page cached on a browser expires.
  132. * @param string|int|DateTime time, value 0 means "until the browser is closed"
  133. * @return HttpResponse provides a fluent interface
  134. * @throws InvalidStateException if HTTP headers have been sent
  135. */
  136. public function setExpiration($time)
  137. {
  138. if (!$time) { // no cache
  139. $this->setHeader('Cache-Control', 's-maxage=0, max-age=0, must-revalidate');
  140. $this->setHeader('Expires', 'Mon, 23 Jan 1978 10:00:00 GMT');
  141. return $this;
  142. }
  143. $time = Tools::createDateTime($time);
  144. $this->setHeader('Cache-Control', 'max-age=' . ($time->format('U') - time()));
  145. $this->setHeader('Expires', self::date($time));
  146. return $this;
  147. }
  148. /**
  149. * Checks if headers have been sent.
  150. * @return bool
  151. */
  152. public function isSent()
  153. {
  154. return headers_sent();
  155. }
  156. /**
  157. * Return the value of the HTTP header.
  158. * @param string
  159. * @param mixed
  160. * @return mixed
  161. */
  162. public function getHeader($header, $default = NULL)
  163. {
  164. $header .= ':';
  165. $len = strlen($header);
  166. foreach (headers_list() as $item) {
  167. if (strncasecmp($item, $header, $len) === 0) {
  168. return ltrim(substr($item, $len));
  169. }
  170. }
  171. return $default;
  172. }
  173. /**
  174. * Returns a list of headers to sent.
  175. * @return array
  176. */
  177. public function getHeaders()
  178. {
  179. $headers = array();
  180. foreach (headers_list() as $header) {
  181. $a = strpos($header, ':');
  182. $headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
  183. }
  184. return $headers;
  185. }
  186. /**
  187. * Returns HTTP valid date format.
  188. * @param string|int|DateTime
  189. * @return string
  190. */
  191. public static function date($time = NULL)
  192. {
  193. $time = Tools::createDateTime($time);
  194. $time->setTimezone(new DateTimeZone('GMT'));
  195. return $time->format('D, d M Y H:i:s \G\M\T');
  196. }
  197. /**
  198. * Enables compression. (warning: may not work)
  199. * @return bool
  200. */
  201. public function enableCompression()
  202. {
  203. if (headers_sent()) {
  204. return FALSE;
  205. }
  206. if ($this->getHeader('Content-Encoding') !== NULL) {
  207. return FALSE; // called twice
  208. }
  209. $ok = ob_gzhandler('', PHP_OUTPUT_HANDLER_START);
  210. if ($ok === FALSE) {
  211. return FALSE; // not allowed
  212. }
  213. if (function_exists('ini_set')) {
  214. ini_set('zlib.output_compression', 'Off');
  215. ini_set('zlib.output_compression_level', '6');
  216. }
  217. ob_start('ob_gzhandler', 1);
  218. return TRUE;
  219. }
  220. /**
  221. * @return void
  222. */
  223. public function __destruct()
  224. {
  225. if (self::$fixIE) {
  226. // Sends invisible garbage for IE.
  227. if (!isset($_SERVER['HTTP_USER_AGENT']) || strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') === FALSE) return;
  228. if (!in_array($this->code, array(400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505), TRUE)) return;
  229. if ($this->getHeader('Content-Type', 'text/html') !== 'text/html') return;
  230. $s = " \t\r\n";
  231. for ($i = 2e3; $i; $i--) echo $s{rand(0, 3)};
  232. self::$fixIE = FALSE;
  233. }
  234. }
  235. /**
  236. * Sends a cookie.
  237. * @param string name of the cookie
  238. * @param string value
  239. * @param string|int|DateTime expiration time, value 0 means "until the browser is closed"
  240. * @param string
  241. * @param string
  242. * @param bool
  243. * @return HttpResponse provides a fluent interface
  244. * @throws InvalidStateException if HTTP headers have been sent
  245. */
  246. public function setCookie($name, $value, $time, $path = NULL, $domain = NULL, $secure = NULL)
  247. {
  248. if (headers_sent($file, $line)) {
  249. throw new InvalidStateException("Cannot set cookie after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
  250. }
  251. setcookie(
  252. $name,
  253. $value,
  254. $time ? Tools::createDateTime($time)->format('U') : 0,
  255. $path === NULL ? $this->cookiePath : (string) $path,
  256. $domain === NULL ? $this->cookieDomain : (string) $domain, // . '; httponly'
  257. $secure === NULL ? $this->cookieSecure : (bool) $secure,
  258. TRUE // added in PHP 5.2.0.
  259. );
  260. return $this;
  261. }
  262. /**
  263. * Deletes a cookie.
  264. * @param string name of the cookie.
  265. * @param string
  266. * @param string
  267. * @param bool
  268. * @return void
  269. * @throws InvalidStateException if HTTP headers have been sent
  270. */
  271. public function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL)
  272. {
  273. if (headers_sent($file, $line)) {
  274. throw new InvalidStateException("Cannot delete cookie after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
  275. }
  276. setcookie(
  277. $name,
  278. FALSE,
  279. 254400000,
  280. $path === NULL ? $this->cookiePath : (string) $path,
  281. $domain === NULL ? $this->cookieDomain : (string) $domain, // . '; httponly'
  282. $secure === NULL ? $this->cookieSecure : (bool) $secure,
  283. TRUE // added in PHP 5.2.0.
  284. );
  285. }
  286. }