Source for file HttpResponse.php

Documentation is available at HttpResponse.php

  1. 1: <?php
  2. 2:  
  3. 3: /**
  4. 4:  * Nette Framework
  5. 5:  *
  6. 6:  * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  7. 7:  *
  8. 8:  * This source file is subject to the "Nette license" that is bundled
  9. 9:  * with this package in the file license.txt.
  10. 10:  *
  11. 11:  * For more information please see https://nette.org
  12. 12:  *
  13. 13:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  14. 14:  * @license    https://nette.org/license  Nette license
  15. 15:  * @link       https://nette.org
  16. 16:  * @category   Nette
  17. 17:  * @package    Nette\Web
  18. 18:  * @version    $Id$
  19. 19:  */
  20. 20:  
  21. 21:  
  22. 22:  
  23. 23: require_once dirname(__FILE__'/../Object.php';
  24. 24:  
  25. 25: require_once dirname(__FILE__'/../Web/IHttpResponse.php';
  26. 26:  
  27. 27:  
  28. 28:  
  29. 29: /**
  30. 30:  * HttpResponse class.
  31. 31:  *
  32. 32:  * @author     David Grudl
  33. 33:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  34. 34:  * @package    Nette\Web
  35. 35:  */
  36. 36: final class HttpResponse extends Object implements IHttpResponse
  37. 37: {
  38. 38:     /** @var bool  Send invisible garbage for IE 6? */
  39. 39:     private static $fixIE TRUE;
  40. 40:  
  41. 41:     /** @var string The domain in which the cookie will be available */
  42. 42:     public $cookieDomain = '';
  43. 43:  
  44. 44:     /** @var string The path in which the cookie will be available */
  45. 45:     public $cookiePath = '';
  46. 46:  
  47. 47:     /** @var string The path in which the cookie will be available */
  48. 48:     public $cookieSecure = FALSE;
  49. 49:  
  50. 50:     /** @var int HTTP response code */
  51. 51:     private $code self::S200_OK;
  52. 52:  
  53. 53:  
  54. 54:  
  55. 55:     /**
  56. 56:      * Sets HTTP response code.
  57. 57:      * @param  int 
  58. 58:      * @return bool 
  59. 59:      * @throws InvalidArgumentException  if code is invalid
  60. 60:      * @throws InvalidStateException  if HTTP headers have been sent
  61. 61:      */
  62. 62:     public function setCode($code)
  63. 63:     {
  64. 64:         $code = (int) $code;
  65. 65:  
  66. 66:         static $allowed array(
  67. 67:             200=>1201=>1202=>1203=>1204=>1205=>1206=>1,
  68. 68:             300=>1301=>1302=>1303=>1304=>1307=>1,
  69. 69:             400=>1401=>1403=>1404=>1406=>1408=>1410=>1412=>1415=>1416=>1,
  70. 70:             500=>1501=>1503=>1505=>1
  71. 71:         );
  72. 72:  
  73. 73:         if (!isset($allowed[$code])) {
  74. 74:             throw new InvalidArgumentException("Bad HTTP response '$code'.");
  75. 75:  
  76. 76:         elseif (headers_sent($file$line)) {
  77. 77:             throw new InvalidStateException("Cannot set HTTP code after HTTP headers have been sent" ($file " (output started at $file:$line)."."));
  78. 78:  
  79. 79:         else {
  80. 80:             $this->code $code;
  81. 81:             $protocol isset($_SERVER['SERVER_PROTOCOL']$_SERVER['SERVER_PROTOCOL''HTTP/1.1';
  82. 82:             header($protocol ' ' $codeTRUE$code);
  83. 83:             return TRUE;
  84. 84:         }
  85. 85:     }
  86. 86:  
  87. 87:  
  88. 88:  
  89. 89:     /**
  90. 90:      * Returns HTTP response code.
  91. 91:      * @return int 
  92. 92:      */
  93. 93:     public function getCode()
  94. 94:     {
  95. 95:         return $this->code;
  96. 96:     }
  97. 97:  
  98. 98:  
  99. 99:  
  100. 100:     /**
  101. 101:      * Sends a HTTP header and replaces a previous one.
  102. 102:      * @param  string  header name
  103. 103:      * @param  string  header value
  104. 104:      * @return void 
  105. 105:      * @throws InvalidStateException  if HTTP headers have been sent
  106. 106:      */
  107. 107:     public function setHeader($name$value$replace TRUE)
  108. 108:     {
  109. 109:         if (headers_sent($file$line)) {
  110. 110:             throw new InvalidStateException("Cannot send header after HTTP headers have been sent" ($file " (output started at $file:$line)."."));
  111. 111:         }
  112. 112:  
  113. 113:         header($name ': ' $value$replace$this->code);
  114. 114:     }
  115. 115:  
  116. 116:  
  117. 117:  
  118. 118:     /**
  119. 119:      * Adds HTTP header.
  120. 120:      * @param  string  header name
  121. 121:      * @param  string  header value
  122. 122:      * @return void 
  123. 123:      * @throws InvalidStateException  if HTTP headers have been sent
  124. 124:      */
  125. 125:     public function addHeader($name$value)
  126. 126:     {
  127. 127:         if (headers_sent($file$line)) {
  128. 128:             throw new InvalidStateException("Cannot send header after HTTP headers have been sent" ($file " (output started at $file:$line)."."));
  129. 129:         }
  130. 130:  
  131. 131:         header($name ': ' $valueFALSE$this->code);
  132. 132:     }
  133. 133:  
  134. 134:  
  135. 135:  
  136. 136:     /**
  137. 137:      * Sends a Content-type HTTP header.
  138. 138:      * @param  string  mime-type
  139. 139:      * @param  string  charset
  140. 140:      * @return void 
  141. 141:      * @throws InvalidStateException  if HTTP headers have been sent
  142. 142:      */
  143. 143:     public function setContentType($type$charset NULL)
  144. 144:     {
  145. 145:         $this->setHeader('Content-Type'$type ($charset '; charset=' $charset ''));
  146. 146:     }
  147. 147:  
  148. 148:  
  149. 149:  
  150. 150:     /**
  151. 151:      * Redirects to a new URL. Note: call exit() after it.
  152. 152:      * @param  string  URL
  153. 153:      * @param  int     HTTP code
  154. 154:      * @return void 
  155. 155:      * @throws InvalidStateException  if HTTP headers have been sent
  156. 156:      */
  157. 157:     public function redirect($url$code self::S302_FOUND)
  158. 158:     {
  159. 159:         $this->setCode($code);
  160. 160:         $this->setHeader('Location'$url);
  161. 161:         $url htmlSpecialChars($url);
  162. 162:         echo "<h1>Redirect</h1>\n\n<p><a href=\"$url\">Please click here to continue</a>.</p>";
  163. 163:     }
  164. 164:  
  165. 165:  
  166. 166:  
  167. 167:     /**
  168. 168:      * Sets the number of seconds before a page cached on a browser expires.
  169. 169:      * @param  int  timestamp or number of seconds
  170. 170:      * @return void 
  171. 171:      * @throws InvalidStateException  if HTTP headers have been sent
  172. 172:      */
  173. 173:     public function expire($time)
  174. 174:     {
  175. 175:         if ($time 0{
  176. 176:             if ($time <= Tools::YEAR{
  177. 177:                 $time += time();
  178. 178:             }
  179. 179:             $this->setHeader('Cache-Control''max-age=' ($time time())',must-revalidate');
  180. 180:             $this->setHeader('Expires'self::date($time));
  181. 181:  
  182. 182:         else // no cache
  183. 183:             $this->setHeader('Expires''Mon, 23 Jan 1978 10:00:00 GMT');
  184. 184:             $this->setHeader('Cache-Control''s-maxage=0, max-age=0, must-revalidate');
  185. 185:         }
  186. 186:     }
  187. 187:  
  188. 188:  
  189. 189:  
  190. 190:     /**
  191. 191:      * Checks if headers have been sent.
  192. 192:      * @return bool 
  193. 193:      */
  194. 194:     public function isSent()
  195. 195:     {
  196. 196:         return headers_sent();
  197. 197:     }
  198. 198:  
  199. 199:  
  200. 200:  
  201. 201:     /**
  202. 202:      * Returns a list of headers to sent.
  203. 203:      * @return array 
  204. 204:      */
  205. 205:     public function getHeaders()
  206. 206:     {
  207. 207:         $headers array();
  208. 208:         foreach (headers_list(as $header{
  209. 209:             $a strpos($header':');
  210. 210:             $headers[substr($header0$a)substr($header$a 2);
  211. 211:         }
  212. 212:         return $headers;
  213. 213:     }
  214. 214:  
  215. 215:  
  216. 216:  
  217. 217:     /**
  218. 218:      * Returns HTTP valid date format.
  219. 219:      * @param  int  timestamp
  220. 220:      * @return string 
  221. 221:      */
  222. 222:     public static function date($time NULL)
  223. 223:     {
  224. 224:         return gmdate('D, d M Y H:i:s \G\M\T'$time === NULL time($time);
  225. 225:     }
  226. 226:  
  227. 227:  
  228. 228:  
  229. 229:     /**
  230. 230:      * Enables compression. (warning: may not work)
  231. 231:      * @return bool 
  232. 232:      */
  233. 233:     public function enableCompression()
  234. 234:     {
  235. 235:         if (headers_sent()) return FALSE;
  236. 236:  
  237. 237:         $headers $this->getHeaders();
  238. 238:         if (isset($headers['Content-Encoding'])) {
  239. 239:             return FALSE// called twice
  240. 240:         }
  241. 241:  
  242. 242:         $ok ob_gzhandler(''PHP_OUTPUT_HANDLER_START);
  243. 243:         if ($ok === FALSE{
  244. 244:             return FALSE// not allowed
  245. 245:         }
  246. 246:  
  247. 247:         if (function_exists('ini_set')) {
  248. 248:             ini_set('zlib.output_compression''Off');
  249. 249:             ini_set('zlib.output_compression_level''6');
  250. 250:         }
  251. 251:         ob_start('ob_gzhandler');
  252. 252:         return TRUE;
  253. 253:     }
  254. 254:  
  255. 255:  
  256. 256:  
  257. 257:     /**
  258. 258:      * @return void 
  259. 259:      */
  260. 260:     public function __destruct()
  261. 261:     {
  262. 262:         if (self::$fixIE{
  263. 263:             // Sends invisible garbage for IE.
  264. 264:             if (!isset($_SERVER['HTTP_USER_AGENT']|| strpos($_SERVER['HTTP_USER_AGENT']'MSIE '=== FALSEreturn;
  265. 265:             if (!in_array($this->codearray(400403404405406408409410500501505)TRUE)) return;
  266. 266:             $headers $this->getHeaders();
  267. 267:             if (isset($headers['Content-Type']&& $headers['Content-Type'!== 'text/html'return;
  268. 268:             $s " \t\r\n";
  269. 269:             for ($i 2e3$i$i--echo $s{rand(03)};
  270. 270:             self::$fixIE FALSE;
  271. 271:         }
  272. 272:     }
  273. 273:  
  274. 274:  
  275. 275:  
  276. 276:     /**
  277. 277:      * Sends a cookie.
  278. 278:      * @param  string name of the cookie
  279. 279:      * @param  string value
  280. 280:      * @param  int expiration as unix timestamp or number of seconds; Value 0 means "until the browser is closed"
  281. 281:      * @param  string 
  282. 282:      * @param  string 
  283. 283:      * @param  bool 
  284. 284:      * @return void 
  285. 285:      * @throws InvalidStateException  if HTTP headers have been sent
  286. 286:      */
  287. 287:     public function setCookie($name$value$expire$path NULL$domain NULL$secure NULL)
  288. 288:     {
  289. 289:         if (headers_sent($file$line)) {
  290. 290:             throw new InvalidStateException("Cannot set cookie after HTTP headers have been sent" ($file " (output started at $file:$line)."."));
  291. 291:         }
  292. 292:  
  293. 293:         setcookie(
  294. 294:             $name,
  295. 295:             $value,
  296. 296:             $expire && $expire <= Tools::YEAR $expire time($expire,
  297. 297:             $path === NULL $this->cookiePath : (string) $path,
  298. 298:             $domain === NULL $this->cookieDomain : (string) $domain//  . '; httponly'
  299. 299:             $secure === NULL $this->cookieSecure : (bool) $secure,
  300. 300:             TRUE // added in PHP 5.2.0.
  301. 301:         );
  302. 302:     }
  303. 303:  
  304. 304:  
  305. 305:  
  306. 306:     /**
  307. 307:      * Deletes a cookie.
  308. 308:      * @param  string name of the cookie.
  309. 309:      * @param  string 
  310. 310:      * @param  string 
  311. 311:      * @param  bool 
  312. 312:      * @return void 
  313. 313:      * @throws InvalidStateException  if HTTP headers have been sent
  314. 314:      */
  315. 315:     public function deleteCookie($name$path NULL$domain NULL$secure NULL)
  316. 316:     {
  317. 317:         if (headers_sent($file$line)) {
  318. 318:             throw new InvalidStateException("Cannot delete cookie after HTTP headers have been sent" ($file " (output started at $file:$line)."."));
  319. 319:         }
  320. 320:  
  321. 321:         setcookie(
  322. 322:             $name,
  323. 323:             FALSE,
  324. 324:             254400000,
  325. 325:             $path === NULL $this->cookiePath : (string) $path,
  326. 326:             $domain === NULL $this->cookieDomain : (string) $domain//  . '; httponly'
  327. 327:             $secure === NULL $this->cookieSecure : (bool) $secure,
  328. 328:             TRUE // added in PHP 5.2.0.
  329. 329:         );
  330. 330:     }
  331. 331: