Files
typecho/var/Typecho/Response.php
joyqi 3caebb3b20 v1.3.0 (#1661)
* Add feed widget

* add feed render

* Add CommentPage widget

* New theme (#1390)

* 调整忽略目录

* add theme

* fix theme scss build

Co-authored-by: fen <f3nb0x@gmail.com>

* s/is_writeable/is_writable/g

* New upgrade method

* merge new fixes from master

* add pgsql ssl mode support (ref #1600) (#1623)

* Feat/code refactor (#1626)

* remove all magic methods, add type for class properties

* refactor codes

* fix all

* refactor code

* fix type

* fix all

* fix request is method

* fix all

* fix router

* fix get page

* fix 1.3.0 upgrade

* [feat] support high resolution avatar

* fix types in i18n component

* Implement Ctrl+S or Command+S for save draft (#1628)

* Implement Ctrl+S or Command+S for save draft

* rename

* add Typecho.savePost

* fix upload file size

* add new uploader

* replace new uploader

* fix textarea change

* fix preview

* refactor post edit

* fix issue

* fix page edit

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* fix #1632

* Add svg to image types

* Feat/tree pages (#1646)

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Support IDN (#1629)

* Support IDN

* use js

* Optimize code

* Optimize code

* fix URL script

* remove unnecessary use

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* fix input element

* fix #1651, close #1653

* Use json instead of serialize (#1624)

* Use json instead of serialize

* Fix Upgrade code

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Fix typo

* remove proxy methods

* remove unnecessary useage

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* Fix Prevent XSS vulnerability in default theme (#1654)

* Fix Prevent XSS vulnerability in default theme

* Update var/Typecho/Db/Adapter/Pdo.php

* fix the getter

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* add throwCallback to widget response

* fix: cut down fields when selecting recent posts

* fix typo errors

* fix typo errors

* fix http client cookie

* add throw finish

* fix theme lang

* fix default theme

* fix query

* add open graph and twitter card support
add canonical link

* fix canonical link meta

* fix theme classic-22

* remove unnecessary scss file when packaging

* init plugin signal

* improve: remove feather-icon js file

* fix: typo

* improve: post detail layout

* fix tags saving

* improve: nav search

* fix: theme screenshot

* fix: theme page layout

* remove php 7.2/7.3 env

---------

Co-authored-by: fen <f3nb0x@gmail.com>
Co-authored-by: Lu Fei <52o@qq52o.cn>
2023-12-30 23:02:25 +08:00

355 lines
7.8 KiB
PHP

<?php
namespace Typecho;
use Typecho\Widget\Terminal;
/**
* Typecho公用方法
*
* @category typecho
* @package Response
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
*/
class Response
{
/**
* http code
*
* @access private
* @var array
*/
private const HTTP_CODE = [
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported'
];
//默认的字符编码
/**
* 单例句柄
*
* @access private
* @var Response
*/
private static Response $instance;
/**
* 字符编码
*
* @var string
*/
private string $charset = 'UTF-8';
/**
* @var string
*/
private string $contentType = 'text/html';
/**
* @var callable[]
*/
private array $responders = [];
/**
* @var array
*/
private array $cookies = [];
/**
* @var array
*/
private array $headers = [];
/**
* @var int
*/
private int $status = 200;
/**
* @var bool
*/
private bool $enableAutoSendHeaders = true;
/**
* @var bool
*/
private bool $sandbox = false;
/**
* init responder
*/
public function __construct()
{
$this->clean();
}
/**
* 获取单例句柄
*
* @return Response
*/
public static function getInstance(): Response
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* @return $this
*/
public function beginSandbox(): Response
{
$this->sandbox = true;
return $this;
}
/**
* @return $this
*/
public function endSandbox(): Response
{
$this->sandbox = false;
return $this;
}
/**
* @param bool $enable
*/
public function enableAutoSendHeaders(bool $enable = true)
{
$this->enableAutoSendHeaders = $enable;
}
/**
* clean all
*/
public function clean()
{
$this->headers = [];
$this->cookies = [];
$this->status = 200;
$this->responders = [];
$this->setContentType('text/html');
}
/**
* send all headers
*/
public function sendHeaders()
{
if ($this->sandbox) {
return;
}
$sentHeaders = [];
foreach (headers_list() as $header) {
[$key] = explode(':', $header, 2);
$sentHeaders[] = strtolower(trim($key));
}
header('HTTP/1.1 ' . $this->status . ' ' . self::HTTP_CODE[$this->status], true, $this->status);
// set header
foreach ($this->headers as $name => $value) {
if (!in_array(strtolower($name), $sentHeaders)) {
header($name . ': ' . $value);
}
}
// set cookie
foreach ($this->cookies as $cookie) {
[$key, $value, $timeout, $path, $domain, $secure, $httponly] = $cookie;
if ($timeout > 0) {
$now = time();
$timeout += $timeout > $now - 86400 ? 0 : $now;
} elseif ($timeout < 0) {
$timeout = 1;
}
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain, $secure, $httponly);
}
}
/**
* respond data
* @throws Terminal
*/
public function respond()
{
if ($this->sandbox) {
throw new Terminal('sandbox mode');
}
if ($this->enableAutoSendHeaders) {
$this->sendHeaders();
}
foreach ($this->responders as $responder) {
call_user_func($responder, $this);
}
exit;
}
/**
* 设置HTTP状态
*
* @access public
* @param integer $code http代码
* @return $this
*/
public function setStatus(int $code): Response
{
if (!$this->sandbox) {
$this->status = $code;
}
return $this;
}
/**
* 设置http头
*
* @param string $name 名称
* @param string $value 对应值
* @return $this
*/
public function setHeader(string $name, string $value): Response
{
if (!$this->sandbox) {
$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
$this->headers[$name] = $value;
}
return $this;
}
/**
* 设置指定的COOKIE值
*
* @param string $key 指定的参数
* @param mixed $value 设置的值
* @param integer $timeout 过期时间,默认为0,表示随会话时间结束
* @param string $path 路径信息
* @param string|null $domain 域名信息
* @param bool $secure 是否仅可通过安全的 HTTPS 连接传给客户端
* @param bool $httponly 是否仅可通过 HTTP 协议访问
* @return $this
*/
public function setCookie(
string $key,
$value,
int $timeout = 0,
string $path = '/',
string $domain = '',
bool $secure = false,
bool $httponly = false
): Response {
if (!$this->sandbox) {
$this->cookies[] = [$key, $value, $timeout, $path, $domain, $secure, $httponly];
}
return $this;
}
/**
* 在http头部请求中声明类型和字符集
*
* @param string $contentType 文档类型
* @return $this
*/
public function setContentType(string $contentType): Response
{
if (!$this->sandbox) {
$this->contentType = $contentType;
$this->setHeader('Content-Type', $this->contentType . '; charset=' . $this->charset);
}
return $this;
}
/**
* 获取字符集
*
* @return string
*/
public function getCharset(): string
{
return $this->charset;
}
/**
* 设置默认回执编码
*
* @param string $charset 字符集
* @return $this
*/
public function setCharset(string $charset): Response
{
if (!$this->sandbox) {
$this->charset = $charset;
$this->setHeader('Content-Type', $this->contentType . '; charset=' . $this->charset);
}
return $this;
}
/**
* add responder
*
* @param callable $responder
* @return $this
*/
public function addResponder(callable $responder): Response
{
if (!$this->sandbox) {
$this->responders[] = $responder;
}
return $this;
}
}