Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationLatte
      • ApplicationTracy
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsLatte
      • Framework
      • HttpTracy
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy

Classes

  • Context
  • FileUpload
  • Helpers
  • Request
  • RequestFactory
  • Response
  • Session
  • SessionSection
  • Url
  • UrlScript
  • UserStorage

Interfaces

  • IRequest
  • IResponse
  • ISessionStorage
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Http;
  9: 
 10: use Nette,
 11:     Nette\Utils\DateTime;
 12: 
 13: 
 14: /**
 15:  * HttpResponse class.
 16:  *
 17:  * @author     David Grudl
 18:  *
 19:  * @property   int $code
 20:  * @property-read bool $sent
 21:  * @property-read array $headers
 22:  */
 23: class Response extends Nette\Object implements IResponse
 24: {
 25:     /** @var bool  Send invisible garbage for IE 6? */
 26:     private static $fixIE = TRUE;
 27: 
 28:     /** @var string The domain in which the cookie will be available */
 29:     public $cookieDomain = '';
 30: 
 31:     /** @var string The path in which the cookie will be available */
 32:     public $cookiePath = '/';
 33: 
 34:     /** @var string Whether the cookie is available only through HTTPS */
 35:     public $cookieSecure = FALSE;
 36: 
 37:     /** @var string Whether the cookie is hidden from client-side */
 38:     public $cookieHttpOnly = TRUE;
 39: 
 40:     /** @var int HTTP response code */
 41:     private $code = self::S200_OK;
 42: 
 43: 
 44:     public function __construct()
 45:     {
 46:         if (PHP_VERSION_ID >= 50400) {
 47:             if (is_int(http_response_code())) {
 48:                 $this->code = http_response_code();
 49:             }
 50:             header_register_callback($this->removeDuplicateCookies);
 51:         }
 52:     }
 53: 
 54: 
 55:     /**
 56:      * Sets HTTP response code.
 57:      * @param  int
 58:      * @return self
 59:      * @throws Nette\InvalidArgumentException  if code is invalid
 60:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
 61:      */
 62:     public function setCode($code)
 63:     {
 64:         $code = (int) $code;
 65:         if ($code < 100 || $code > 599) {
 66:             throw new Nette\InvalidArgumentException("Bad HTTP response '$code'.");
 67:         }
 68:         self::checkHeaders();
 69:         $this->code = $code;
 70:         $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
 71:         header($protocol . ' ' . $code, TRUE, $code);
 72:         return $this;
 73:     }
 74: 
 75: 
 76:     /**
 77:      * Returns HTTP response code.
 78:      * @return int
 79:      */
 80:     public function getCode()
 81:     {
 82:         return $this->code;
 83:     }
 84: 
 85: 
 86:     /**
 87:      * Sends a HTTP header and replaces a previous one.
 88:      * @param  string  header name
 89:      * @param  string  header value
 90:      * @return self
 91:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
 92:      */
 93:     public function setHeader($name, $value)
 94:     {
 95:         self::checkHeaders();
 96:         if ($value === NULL) {
 97:             header_remove($name);
 98:         } elseif (strcasecmp($name, 'Content-Length') === 0 && ini_get('zlib.output_compression')) {
 99:             // ignore, PHP bug #44164
100:         } else {
101:             header($name . ': ' . $value, TRUE, $this->code);
102:         }
103:         return $this;
104:     }
105: 
106: 
107:     /**
108:      * Adds HTTP header.
109:      * @param  string  header name
110:      * @param  string  header value
111:      * @return self
112:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
113:      */
114:     public function addHeader($name, $value)
115:     {
116:         self::checkHeaders();
117:         header($name . ': ' . $value, FALSE, $this->code);
118:         return $this;
119:     }
120: 
121: 
122:     /**
123:      * Sends a Content-type HTTP header.
124:      * @param  string  mime-type
125:      * @param  string  charset
126:      * @return self
127:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
128:      */
129:     public function setContentType($type, $charset = NULL)
130:     {
131:         $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
132:         return $this;
133:     }
134: 
135: 
136:     /**
137:      * Redirects to a new URL. Note: call exit() after it.
138:      * @param  string  URL
139:      * @param  int     HTTP code
140:      * @return void
141:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
142:      */
143:     public function redirect($url, $code = self::S302_FOUND)
144:     {
145:         $this->setCode($code);
146:         $this->setHeader('Location', $url);
147:         echo "<h1>Redirect</h1>\n\n<p><a href=\"" . htmlSpecialChars($url, ENT_IGNORE | ENT_QUOTES) . "\">Please click here to continue</a>.</p>";
148:     }
149: 
150: 
151:     /**
152:      * Sets the number of seconds before a page cached on a browser expires.
153:      * @param  string|int|DateTime  time, value 0 means "until the browser is closed"
154:      * @return self
155:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
156:      */
157:     public function setExpiration($time)
158:     {
159:         if (!$time) { // no cache
160:             $this->setHeader('Cache-Control', 's-maxage=0, max-age=0, must-revalidate');
161:             $this->setHeader('Expires', 'Mon, 23 Jan 1978 10:00:00 GMT');
162:             return $this;
163:         }
164: 
165:         $time = DateTime::from($time);
166:         $this->setHeader('Cache-Control', 'max-age=' . ($time->format('U') - time()));
167:         $this->setHeader('Expires', self::date($time));
168:         return $this;
169:     }
170: 
171: 
172:     /**
173:      * Checks if headers have been sent.
174:      * @return bool
175:      */
176:     public function isSent()
177:     {
178:         return headers_sent();
179:     }
180: 
181: 
182:     /**
183:      * Return the value of the HTTP header.
184:      * @param  string
185:      * @param  mixed
186:      * @return mixed
187:      */
188:     public function getHeader($header, $default = NULL)
189:     {
190:         $header .= ':';
191:         $len = strlen($header);
192:         foreach (headers_list() as $item) {
193:             if (strncasecmp($item, $header, $len) === 0) {
194:                 return ltrim(substr($item, $len));
195:             }
196:         }
197:         return $default;
198:     }
199: 
200: 
201:     /**
202:      * Returns a list of headers to sent.
203:      * @return array
204:      */
205:     public function getHeaders()
206:     {
207:         $headers = array();
208:         foreach (headers_list() as $header) {
209:             $a = strpos($header, ':');
210:             $headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
211:         }
212:         return $headers;
213:     }
214: 
215: 
216:     /**
217:      * Returns HTTP valid date format.
218:      * @param  string|int|DateTime
219:      * @return string
220:      */
221:     public static function date($time = NULL)
222:     {
223:         $time = DateTime::from($time);
224:         $time->setTimezone(new \DateTimeZone('GMT'));
225:         return $time->format('D, d M Y H:i:s \G\M\T');
226:     }
227: 
228: 
229:     /**
230:      * @return void
231:      */
232:     public function __destruct()
233:     {
234:         if (self::$fixIE && isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== FALSE
235:             && in_array($this->code, array(400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505), TRUE)
236:             && preg_match('#^text/html(?:;|$)#', $this->getHeader('Content-Type', 'text/html'))
237:         ) {
238:             echo Nette\Utils\Random::generate(2e3, " \t\r\n"); // sends invisible garbage for IE
239:             self::$fixIE = FALSE;
240:         }
241:     }
242: 
243: 
244:     /**
245:      * Sends a cookie.
246:      * @param  string name of the cookie
247:      * @param  string value
248:      * @param  string|int|DateTime  expiration time, value 0 means "until the browser is closed"
249:      * @param  string
250:      * @param  string
251:      * @param  bool
252:      * @param  bool
253:      * @return self
254:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
255:      */
256:     public function setCookie($name, $value, $time, $path = NULL, $domain = NULL, $secure = NULL, $httpOnly = NULL)
257:     {
258:         self::checkHeaders();
259:         setcookie(
260:             $name,
261:             $value,
262:             $time ? DateTime::from($time)->format('U') : 0,
263:             $path === NULL ? $this->cookiePath : (string) $path,
264:             $domain === NULL ? $this->cookieDomain : (string) $domain,
265:             $secure === NULL ? $this->cookieSecure : (bool) $secure,
266:             $httpOnly === NULL ? $this->cookieHttpOnly : (bool) $httpOnly
267:         );
268:         $this->removeDuplicateCookies();
269:         return $this;
270:     }
271: 
272: 
273:     /**
274:      * Deletes a cookie.
275:      * @param  string name of the cookie.
276:      * @param  string
277:      * @param  string
278:      * @param  bool
279:      * @return void
280:      * @throws Nette\InvalidStateException  if HTTP headers have been sent
281:      */
282:     public function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL)
283:     {
284:         $this->setCookie($name, FALSE, 0, $path, $domain, $secure);
285:     }
286: 
287: 
288:     /**
289:      * Removes duplicate cookies from response.
290:      * @return void
291:      */
292:     public function removeDuplicateCookies()
293:     {
294:         if (headers_sent($file, $line) || ini_get('suhosin.cookie.encrypt')) {
295:             return;
296:         }
297: 
298:         $flatten = array();
299:         foreach (headers_list() as $header) {
300:             if (preg_match('#^Set-Cookie: .+?=#', $header, $m)) {
301:                 $flatten[$m[0]] = $header;
302:                 header_remove('Set-Cookie');
303:             }
304:         }
305:         foreach (array_values($flatten) as $key => $header) {
306:             header($header, $key === 0);
307:         }
308:     }
309: 
310: 
311:     private function checkHeaders()
312:     {
313:         if (headers_sent($file, $line)) {
314:             throw new Nette\InvalidStateException('Cannot send header after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));
315:         } elseif (ob_get_length() && !array_filter(ob_get_status(TRUE), function($i) { return !$i['chunk_size']; })) {
316:             trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try OutputDebugger or start session earlier.', E_USER_NOTICE);
317:         }
318:     }
319: 
320: }
321: 
Nette 2.2.2 API API documentation generated by ApiGen 2.8.0