PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Trinity/Web/Response.php

http://github.com/zyxist/Trinity
PHP | 309 lines | 135 code | 35 blank | 139 comment | 14 complexity | a7a93b064874c44caf1bbdbeb113bdc5 MD5 | raw file
  1. <?php
  2. /*
  3. * TRINITY FRAMEWORK <http://www.invenzzia.org>
  4. *
  5. * This file is subject to the new BSD license that is bundled
  6. * with this package in the file LICENSE. It is also available through
  7. * WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
  8. *
  9. * Copyright (c) Invenzzia Group <http://www.invenzzia.org>
  10. * and other contributors. See website for details.
  11. */
  12. namespace Trinity\Web;
  13. /**
  14. * The abstract HTTP response class responsible for flushing the output
  15. * and managing headers.
  16. *
  17. * @author Tomasz Jędrzejewski
  18. * @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
  19. * @license http://www.invenzzia.org/license/new-bsd New BSD License
  20. */
  21. abstract class Response
  22. {
  23. /**
  24. * The HTTP response code.
  25. * @var int
  26. */
  27. private $_responseCode = 200;
  28. /**
  29. * The response body
  30. */
  31. private $_body = '';
  32. /**
  33. * The list of HTTP headers
  34. * @var array
  35. */
  36. private $_headers = array();
  37. /**
  38. * The list of raw headers.
  39. * @var array
  40. */
  41. private $_rawHeaders = array();
  42. /**
  43. * Are the headers sent?
  44. * @var boolean
  45. */
  46. private $_headersSent = false;
  47. /**
  48. * Body generator
  49. * @var callback
  50. */
  51. private $_bodyGenerator = null;
  52. /**
  53. * If set to true, an exception is throw if the headers
  54. * have already been sent.
  55. * @var boolean
  56. */
  57. public $throwExceptionsOnHeadersSent = true;
  58. /**
  59. * Sets a HTTP header with the specified value.
  60. *
  61. * @throws \Trinity\Web\Response\Exception
  62. * @param string $name The header name
  63. * @param string $value The header value
  64. * @param boolean $replace Replace the header, if already exists?
  65. * @return Response Fluent interface.
  66. */
  67. public function setHeader($name, $value, $replace = true)
  68. {
  69. $this->_verifyHeadersSent($name);
  70. if(isset($this->_headers[$name]) && !$replace)
  71. {
  72. throw new Response\Exception('Cannot replace the header '.$name.' - already set.');
  73. }
  74. $this->_headers[$name] = array(
  75. 'value' => (string)$value,
  76. 'replace' => $replace
  77. );
  78. return $this;
  79. } // end setHeader();
  80. /**
  81. * Returns the header value. If the header does not exist, an exception
  82. * is thrown.
  83. *
  84. * @throws \Trinity\Web\Response\Exception
  85. * @param string $name The header name
  86. * @return string
  87. */
  88. public function getHeader($name)
  89. {
  90. if(!isset($this->_headers[$name]))
  91. {
  92. throw new Response\Exception('The header '.$name.' is not defined.');
  93. }
  94. return $this->_headers[$name]['value'];
  95. } // end getHeader();
  96. /**
  97. * Checks if the specified header is set.
  98. *
  99. * @param string $name The header name
  100. * @return boolean
  101. */
  102. public function hasHeader($name)
  103. {
  104. return isset($this->_headers[$name]);
  105. } // end hasHeader();
  106. /**
  107. * Removes the header with the specified name.
  108. *
  109. * @param string $name The header name
  110. * @return Response Fluent interface.
  111. */
  112. public function removeHeader($name)
  113. {
  114. if(isset($this->_headers[$name]))
  115. {
  116. unset($this->_headers[$name]);
  117. }
  118. return $this;
  119. } // end removeHeader();
  120. /**
  121. * Produces the redirect.
  122. *
  123. * @param string $url A fully qualified URL
  124. * @param int $responseCode The response code.
  125. */
  126. public function setRedirect($url, $responseCode = 302)
  127. {
  128. $this->setHeader('Location', $url, true)
  129. ->setResponseCode($responseCode);
  130. } // end setRedirect();
  131. /**
  132. * Checks, if the response is a redirection.
  133. *
  134. * @return boolean
  135. */
  136. public function isRedirect()
  137. {
  138. return isset($this->_headers['Location']);
  139. } // end isRedirect();
  140. /**
  141. * Sets the response code for this response.
  142. *
  143. * @throws \Trinity\Web\Response\Exception
  144. * @param int $code The HTTP response code.
  145. */
  146. public function setResponseCode($code)
  147. {
  148. if(!is_int($code) || $code < 100 || $code > 599)
  149. {
  150. throw new Response_Exception('Invalid HTTP response code: '.$code);
  151. }
  152. $this->_responseCode = $code;
  153. } // end setResponseCode();
  154. /**
  155. * Returns the current response code.
  156. * @return integer
  157. */
  158. public function getResponseCode()
  159. {
  160. return $this->_responseCode;
  161. } // end getResponseCode();
  162. /**
  163. * Sets the body generator.
  164. *
  165. * @throws \Trinity\Web\Response\Exception
  166. * @param callback $generator Body generator callback
  167. * @return Response Fluent interface.
  168. */
  169. public function setBodyGenerator($generator)
  170. {
  171. if(!is_callable($generator))
  172. {
  173. throw new Response\Exception('The specified body generator is not a valid callback.');
  174. }
  175. $this->_bodyGenerator = $generator;
  176. return $this;
  177. } // end setBodyGenerator;
  178. /**
  179. * Returns the current body generator.
  180. *
  181. * @return callback
  182. */
  183. public function getBodyGenerator()
  184. {
  185. return $this->_bodyGenerator;
  186. } // end getBodyGenerator();
  187. /**
  188. * Sets the HTTP body.
  189. * @param string $body The HTTP body
  190. */
  191. public function setBody($body)
  192. {
  193. $this->_body = (string)$body;
  194. } // end setBody();
  195. /**
  196. * Appends a new content to the HTTP body.
  197. * @param string $body The body to append
  198. */
  199. public function appendBody($body)
  200. {
  201. $this->_body .= (string)$body;
  202. } // end appendBody();
  203. /**
  204. * Returns the HTTP response body.
  205. *
  206. * @return string
  207. */
  208. public function getBody()
  209. {
  210. return $this->_body;
  211. } // end getBody();
  212. /**
  213. * Sends the HTTP headers.
  214. */
  215. public function sendHeaders()
  216. {
  217. if($this->_headersSent && $this->throwExceptionsOnHeadersSent)
  218. {
  219. throw new Response\Exception('Headers have already been sent.');
  220. }
  221. // Send the HTTP code
  222. header('HTTP/1.1 '.$this->_responseCode);
  223. // Send the headers
  224. foreach($this->_rawHeaders as $header)
  225. {
  226. header($header);
  227. }
  228. foreach($this->_headers as $name => $data)
  229. {
  230. header($name.': '.$data['value'], $data['replace']);
  231. }
  232. $this->_headersSent = true;
  233. } // end sendHeaders();
  234. /**
  235. * Sends the response body.
  236. */
  237. public function sendBody()
  238. {
  239. $this->_headersSent = true;
  240. if($this->_bodyGenerator === null)
  241. {
  242. echo $this->_body;
  243. }
  244. else
  245. {
  246. call_user_func($this->_bodyGenerator);
  247. }
  248. } // end sendBody();
  249. /**
  250. * Sends the entire response.
  251. */
  252. public function sendResponse()
  253. {
  254. $this->sendHeaders();
  255. if(!$this->isRedirect())
  256. {
  257. $this->sendBody();
  258. }
  259. } // end sendResponse();
  260. /**
  261. * Throws an exception, if the headers have been sent and the appropriate
  262. * option is set.
  263. *
  264. * @throws \Trinity\Web\Response\Exception
  265. * @param string $headerName The header name for the informatory purposes
  266. */
  267. private function _verifyHeadersSent($headerName)
  268. {
  269. if($this->_headersSent && $this->throwExceptionsOnHeadersSent)
  270. {
  271. throw new Response\Exception('Cannot set '.$headerName.' - headers have already been sent.');
  272. }
  273. } // end _verifyHeadersSent();
  274. } // end Response;