Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

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