%PDF- %PDF-
| Direktori : /proc/thread-self/root/www/varak.net/losik.varak.net/vendor/nette/http/src/Http/ |
| Current File : //proc/thread-self/root/www/varak.net/losik.varak.net/vendor/nette/http/src/Http/Response.php |
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Http;
use Nette;
use Nette\Utils\DateTime;
/**
* HttpResponse class.
*
* @property-read array $headers
*/
final 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;
/** @deprecated */
public $cookieHttpOnly;
/** @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.
* @return static
* @throws Nette\InvalidArgumentException if code is invalid
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function setCode(int $code, ?string $reason = null)
{
if ($code < 100 || $code > 599) {
throw new Nette\InvalidArgumentException("Bad HTTP response '$code'.");
}
self::checkHeaders();
$this->code = $code;
$protocol = $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1';
$reason = $reason ?? self::ReasonPhrases[$code] ?? 'Unknown status';
header("$protocol $code $reason");
return $this;
}
/**
* Returns HTTP response code.
*/
public function getCode(): int
{
return $this->code;
}
/**
* Sends an HTTP header and overwrites previously sent header of the same name.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function setHeader(string $name, ?string $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);
}
return $this;
}
/**
* Sends an HTTP header and doesn't overwrite previously sent header of the same name.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function addHeader(string $name, string $value)
{
self::checkHeaders();
header($name . ': ' . $value, false);
return $this;
}
/**
* Deletes a previously sent HTTP header.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function deleteHeader(string $name)
{
self::checkHeaders();
header_remove($name);
return $this;
}
/**
* Sends a Content-type HTTP header.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function setContentType(string $type, ?string $charset = null)
{
$this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
return $this;
}
/**
* Response should be downloaded with 'Save as' dialog.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function sendAsFile(string $fileName)
{
$this->setHeader(
'Content-Disposition',
'attachment; filename="' . str_replace('"', '', $fileName) . '"; '
. "filename*=utf-8''" . rawurlencode($fileName)
);
return $this;
}
/**
* Redirects to another URL. Don't forget to quit the script then.
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function redirect(string $url, int $code = self::S302_Found): void
{
$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 expiration of the HTTP document using the `Cache-Control` and `Expires` headers.
* The parameter is either a time interval (as text) or `null`, which disables caching.
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function setExpiration(?string $expire)
{
$this->setHeader('Pragma', null);
if (!$expire) { // 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;
}
$expire = DateTime::from($expire);
$this->setHeader('Cache-Control', 'max-age=' . ($expire->format('U') - time()));
$this->setHeader('Expires', Helpers::formatDate($expire));
return $this;
}
/**
* Returns whether headers have already been sent from the server to the browser,
* so it is no longer possible to send headers or change the response code.
*/
public function isSent(): bool
{
return headers_sent();
}
/**
* Returns the sent HTTP header, or `null` if it does not exist. The parameter is case-insensitive.
*/
public function getHeader(string $header): ?string
{
if (func_num_args() > 1) {
trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED);
}
$header .= ':';
$len = strlen($header);
foreach (headers_list() as $item) {
if (strncasecmp($item, $header, $len) === 0) {
return ltrim(substr($item, $len));
}
}
return null;
}
/**
* Returns all sent HTTP headers as associative array.
*/
public function getHeaders(): array
{
$headers = [];
foreach (headers_list() as $header) {
$a = strpos($header, ':');
$headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
}
return $headers;
}
public function __destruct()
{
if (
self::$fixIE
&& 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(?:;|$)#', (string) $this->getHeader('Content-Type'))
) {
echo Nette\Utils\Random::generate(2000, " \t\r\n"); // sends invisible garbage for IE
self::$fixIE = false;
}
}
/**
* Sends a cookie.
* @param string|int|\DateTimeInterface $expire expiration time, value null means "until the browser session ends"
* @return static
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function setCookie(
string $name,
string $value,
$expire,
?string $path = null,
?string $domain = null,
?bool $secure = null,
?bool $httpOnly = null,
?string $sameSite = null
) {
self::checkHeaders();
$options = [
'expires' => $expire ? (int) DateTime::from($expire)->format('U') : 0,
'path' => $path ?? ($domain ? '/' : $this->cookiePath),
'domain' => $domain ?? ($path ? '' : $this->cookieDomain),
'secure' => $secure ?? $this->cookieSecure,
'httponly' => $httpOnly ?? true,
'samesite' => $sameSite = ($sameSite ?? self::SameSiteLax),
];
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.
* @throws Nette\InvalidStateException if HTTP headers have been sent
*/
public function deleteCookie(string $name, ?string $path = null, ?string $domain = null, ?bool $secure = null): void
{
$this->setCookie($name, '', 0, $path, $domain, $secure);
}
private function checkHeaders(): void
{
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 (array $i): bool { 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 send cookies/start session earlier.');
}
}
}