no message
This commit is contained in:
+322
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\Http;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\DateTime;
|
||||
|
||||
|
||||
/**
|
||||
* HttpResponse class.
|
||||
*
|
||||
* @property-read array $headers
|
||||
*/
|
||||
class Response implements IResponse
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var string The domain in which the cookie will be available */
|
||||
public $cookieDomain = '';
|
||||
|
||||
/** @var string The path in which the cookie will be available */
|
||||
public $cookiePath = '/';
|
||||
|
||||
/** @var bool Whether the cookie is available only through HTTPS */
|
||||
public $cookieSecure = false;
|
||||
|
||||
/** @var bool Whether the cookie is hidden from client-side */
|
||||
public $cookieHttpOnly = true;
|
||||
|
||||
/** @var bool Whether warn on possible problem with data in output buffer */
|
||||
public $warnOnBuffer = true;
|
||||
|
||||
/** @var bool Send invisible garbage for IE 6? */
|
||||
private static $fixIE = true;
|
||||
|
||||
/** @var int HTTP response code */
|
||||
private $code = self::S200_OK;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (is_int($code = http_response_code())) {
|
||||
$this->code = $code;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets HTTP response code.
|
||||
* @param int
|
||||
* @param string
|
||||
* @return static
|
||||
* @throws Nette\InvalidArgumentException if code is invalid
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function setCode($code, $reason = null)
|
||||
{
|
||||
$code = (int) $code;
|
||||
if ($code < 100 || $code > 599) {
|
||||
throw new Nette\InvalidArgumentException("Bad HTTP response '$code'.");
|
||||
}
|
||||
self::checkHeaders();
|
||||
$this->code = $code;
|
||||
|
||||
static $hasReason = [ // hardcoded in PHP
|
||||
100, 101,
|
||||
200, 201, 202, 203, 204, 205, 206,
|
||||
300, 301, 302, 303, 304, 305, 307, 308,
|
||||
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 426, 428, 429, 431,
|
||||
500, 501, 502, 503, 504, 505, 506, 511,
|
||||
];
|
||||
if ($reason || !in_array($code, $hasReason, true)) {
|
||||
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
|
||||
header("$protocol $code " . ($reason ?: 'Unknown status'));
|
||||
} else {
|
||||
http_response_code($code);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTTP response code.
|
||||
* @return int
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a HTTP header and replaces a previous one.
|
||||
* @param string header name
|
||||
* @param string header value
|
||||
* @return static
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function setHeader($name, $value)
|
||||
{
|
||||
self::checkHeaders();
|
||||
if ($value === null) {
|
||||
header_remove($name);
|
||||
} elseif (strcasecmp($name, 'Content-Length') === 0 && ini_get('zlib.output_compression')) {
|
||||
// ignore, PHP bug #44164
|
||||
} else {
|
||||
header($name . ': ' . $value, true, $this->code);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds HTTP header.
|
||||
* @param string header name
|
||||
* @param string header value
|
||||
* @return static
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function addHeader($name, $value)
|
||||
{
|
||||
self::checkHeaders();
|
||||
header($name . ': ' . $value, false, $this->code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a Content-type HTTP header.
|
||||
* @param string mime-type
|
||||
* @param string charset
|
||||
* @return static
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function setContentType($type, $charset = null)
|
||||
{
|
||||
$this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Redirects to a new URL. Note: call exit() after it.
|
||||
* @param string URL
|
||||
* @param int HTTP code
|
||||
* @return void
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function redirect($url, $code = self::S302_FOUND)
|
||||
{
|
||||
$this->setCode($code);
|
||||
$this->setHeader('Location', $url);
|
||||
if (preg_match('#^https?:|^\s*+[a-z0-9+.-]*+[^:]#i', $url)) {
|
||||
$escapedUrl = htmlspecialchars($url, ENT_IGNORE | ENT_QUOTES, 'UTF-8');
|
||||
echo "<h1>Redirect</h1>\n\n<p><a href=\"$escapedUrl\">Please click here to continue</a>.</p>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the number of seconds before a page cached on a browser expires.
|
||||
* @param string|int|\DateTimeInterface time, value 0 means "must-revalidate"
|
||||
* @return static
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function setExpiration($time)
|
||||
{
|
||||
$this->setHeader('Pragma', null);
|
||||
if (!$time) { // no cache
|
||||
$this->setHeader('Cache-Control', 's-maxage=0, max-age=0, must-revalidate');
|
||||
$this->setHeader('Expires', 'Mon, 23 Jan 1978 10:00:00 GMT');
|
||||
return $this;
|
||||
}
|
||||
|
||||
$time = DateTime::from($time);
|
||||
$this->setHeader('Cache-Control', 'max-age=' . ($time->format('U') - time()));
|
||||
$this->setHeader('Expires', Helpers::formatDate($time));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if headers have been sent.
|
||||
* @return bool
|
||||
*/
|
||||
public function isSent()
|
||||
{
|
||||
return headers_sent();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns value of an HTTP header.
|
||||
* @param string
|
||||
* @param string|null
|
||||
* @return string|null
|
||||
*/
|
||||
public function getHeader($header, $default = null)
|
||||
{
|
||||
$header .= ':';
|
||||
$len = strlen($header);
|
||||
foreach (headers_list() as $item) {
|
||||
if (strncasecmp($item, $header, $len) === 0) {
|
||||
return ltrim(substr($item, $len));
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of headers to sent.
|
||||
* @return array (name => value)
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
$headers = [];
|
||||
foreach (headers_list() as $header) {
|
||||
$a = strpos($header, ':');
|
||||
$headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function date($time = null)
|
||||
{
|
||||
trigger_error('Method date() is deprecated, use Nette\Http\Helpers::formatDate() instead.', E_USER_DEPRECATED);
|
||||
return Helpers::formatDate($time);
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (
|
||||
self::$fixIE
|
||||
&& isset($_SERVER['HTTP_USER_AGENT'])
|
||||
&& strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== false
|
||||
&& in_array($this->code, [400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505], true)
|
||||
&& preg_match('#^text/html(?:;|$)#', $this->getHeader('Content-Type'))
|
||||
) {
|
||||
echo Nette\Utils\Random::generate(2e3, " \t\r\n"); // sends invisible garbage for IE
|
||||
self::$fixIE = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a cookie.
|
||||
* @param string name of the cookie
|
||||
* @param string value
|
||||
* @param string|int|\DateTimeInterface expiration time, value 0 means "until the browser is closed"
|
||||
* @param string
|
||||
* @param string
|
||||
* @param bool
|
||||
* @param bool
|
||||
* @param string
|
||||
* @return static
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function setCookie($name, $value, $time, $path = null, $domain = null, $secure = null, $httpOnly = null, $sameSite = null)
|
||||
{
|
||||
self::checkHeaders();
|
||||
$options = [
|
||||
'expires' => $time ? (int) DateTime::from($time)->format('U') : 0,
|
||||
'path' => $path === null ? $this->cookiePath : (string) $path,
|
||||
'domain' => $domain === null ? $this->cookieDomain : (string) $domain,
|
||||
'secure' => $secure === null ? $this->cookieSecure : (bool) $secure,
|
||||
'httponly' => $httpOnly === null ? $this->cookieHttpOnly : (bool) $httpOnly,
|
||||
'samesite' => (string) $sameSite,
|
||||
];
|
||||
if (PHP_VERSION_ID >= 70300) {
|
||||
setcookie($name, $value, $options);
|
||||
} else {
|
||||
setcookie(
|
||||
$name,
|
||||
$value,
|
||||
$options['expires'],
|
||||
$options['path'] . ($sameSite ? "; SameSite=$sameSite" : ''),
|
||||
$options['domain'],
|
||||
$options['secure'],
|
||||
$options['httponly']
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a cookie.
|
||||
* @param string name of the cookie.
|
||||
* @param string
|
||||
* @param string
|
||||
* @param bool
|
||||
* @return void
|
||||
* @throws Nette\InvalidStateException if HTTP headers have been sent
|
||||
*/
|
||||
public function deleteCookie($name, $path = null, $domain = null, $secure = null)
|
||||
{
|
||||
$this->setCookie($name, false, 0, $path, $domain, $secure);
|
||||
}
|
||||
|
||||
|
||||
private function checkHeaders()
|
||||
{
|
||||
if (PHP_SAPI === 'cli') {
|
||||
} elseif (headers_sent($file, $line)) {
|
||||
throw new Nette\InvalidStateException('Cannot send header after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));
|
||||
|
||||
} elseif ($this->warnOnBuffer && ob_get_length() && !array_filter(ob_get_status(true), function ($i) { return !$i['chunk_size']; })) {
|
||||
trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try Tracy\OutputDebugger or start session earlier.');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user