diff --git a/admin/copyright.php b/admin/copyright.php index a952ed6d..15773516 100644 --- a/admin/copyright.php +++ b/admin/copyright.php @@ -1,13 +1,13 @@ diff --git a/admin/custom-fields.php b/admin/custom-fields.php index 98159ef7..39e52ae8 100644 --- a/admin/custom-fields.php +++ b/admin/custom-fields.php @@ -77,6 +77,6 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
- 帮助文档'); ?> + 帮助文档'); ?>
diff --git a/admin/login.php b/admin/login.php index e51d5789..e6ad36c7 100644 --- a/admin/login.php +++ b/admin/login.php @@ -13,7 +13,7 @@ include 'header.php'; ?>
-

+

@@ -25,7 +25,7 @@ include 'header.php';

- +

@@ -183,7 +183,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
cid)): ?> - + diff --git a/admin/manage-medias.php b/admin/manage-medias.php index 3814f1bf..ba8fc36f 100644 --- a/admin/manage-medias.php +++ b/admin/manage-medias.php @@ -36,7 +36,7 @@ $attachments = \Widget\Contents\Attachment\Admin::alloc(); keywords): ?> onclick="value='';name='keywords';" name="keywords"/> + value="filter('html')->keywords; ?>"keywords): ?> onclick="value='';name='keywords';" name="keywords"/> diff --git a/admin/manage-pages.php b/admin/manage-pages.php index d5150765..ef6d59c3 100644 --- a/admin/manage-pages.php +++ b/admin/manage-pages.php @@ -39,7 +39,7 @@ $pages = \Widget\Contents\Page\Admin::alloc(); + value="filter('html')->keywords; ?>" name="keywords"/> diff --git a/admin/manage-posts.php b/admin/manage-posts.php index 17bbc89a..a0b3dd58 100644 --- a/admin/manage-posts.php +++ b/admin/manage-posts.php @@ -26,11 +26,11 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\ diff --git a/var/Typecho/Common.php b/var/Typecho/Common.php index 7dcddc73..02937782 100644 --- a/var/Typecho/Common.php +++ b/var/Typecho/Common.php @@ -168,7 +168,7 @@ namespace Typecho { class Common { /** 程序版本 */ - public const VERSION = '1.2.0'; + public const VERSION = '1.2.1'; /** * 将路径转化为链接 diff --git a/var/Typecho/Db/Adapter/Mysqli.php b/var/Typecho/Db/Adapter/Mysqli.php index 5f417a3c..d40a232d 100644 --- a/var/Typecho/Db/Adapter/Mysqli.php +++ b/var/Typecho/Db/Adapter/Mysqli.php @@ -47,19 +47,30 @@ class Mysqli implements Adapter */ public function connect(Config $config): \mysqli { + $mysqli = mysqli_init(); + if ($mysqli) { + if (!empty($config->sslCa)) { + $mysqli->ssl_set(null, null, $config->sslCa, null, null); - if ( - $this->dbLink = @mysqli_connect( + if (isset($config->sslVerify)) { + $mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, $config->sslVerify); + } + } + + $mysqli->real_connect( $config->host, $config->user, $config->password, $config->database, (empty($config->port) ? null : $config->port) - ) - ) { + ); + + $this->dbLink = $mysqli; + if ($config->charset) { $this->dbLink->query("SET NAMES '{$config->charset}'"); } + return $this->dbLink; } diff --git a/var/Typecho/Db/Adapter/Pdo/Mysql.php b/var/Typecho/Db/Adapter/Pdo/Mysql.php index 29850502..3e2f4c1d 100644 --- a/var/Typecho/Db/Adapter/Pdo/Mysql.php +++ b/var/Typecho/Db/Adapter/Pdo/Mysql.php @@ -51,11 +51,22 @@ class Mysql extends Pdo */ public function init(Config $config): \PDO { + $options = []; + if (!empty($config->sslCa)) { + $options[\PDO::MYSQL_ATTR_SSL_CA] = $config->sslCa; + + if (isset($config->sslVerify)) { + // FIXME: https://github.com/php/php-src/issues/8577 + $options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $config->sslVerify; + } + } + $pdo = new \PDO( !empty($config->dsn) ? $config->dsn : "mysql:dbname={$config->database};host={$config->host};port={$config->port}", $config->user, - $config->password + $config->password, + $options ); $pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); diff --git a/var/Typecho/Widget/Request.php b/var/Typecho/Widget/Request.php index d6d6d0c7..4c1999c6 100644 --- a/var/Typecho/Widget/Request.php +++ b/var/Typecho/Widget/Request.php @@ -19,6 +19,8 @@ class Request private const FILTERS = [ 'int' => 'intval', 'integer' => 'intval', + 'encode' => 'urlencode', + 'html' => 'htmlspecialchars', 'search' => ['\Typecho\Common', 'filterSearchQuery'], 'xss' => ['\Typecho\Common', 'removeXSS'], 'url' => ['\Typecho\Common', 'safeUrl'], @@ -83,7 +85,7 @@ class Request } /** - * 设置过滤器 + * Add filter to request * * @param string|callable ...$filters * @return $this @@ -91,8 +93,10 @@ class Request public function filter(...$filters): Request { foreach ($filters as $filter) { - $this->filter[] = is_string($filter) && isset(self::FILTERS[$filter]) - ? self::FILTERS[$filter] : $filter; + $this->filter[] = $this->wrapFilter( + is_string($filter) && isset(self::FILTERS[$filter]) + ? self::FILTERS[$filter] : $filter + ); } return $this; @@ -344,4 +348,18 @@ class Request return $value; } + + /** + * Wrap a filter to make sure it always receives a string. + * + * @param callable $filter + * + * @return callable + */ + private function wrapFilter(callable $filter): callable + { + return function ($value) use ($filter) { + return call_user_func($filter, $value ?? ''); + }; + } } diff --git a/var/Widget/Ajax.php b/var/Widget/Ajax.php index 1b3b1d6a..ab064398 100644 --- a/var/Widget/Ajax.php +++ b/var/Widget/Ajax.php @@ -47,7 +47,7 @@ class Ajax extends BaseOptions implements ActionInterface $result = ['available' => 0]; try { - $client->send('http://typecho.org/version.json'); + $client->send('https://typecho.org/version.json'); /** 匹配内容体 */ $response = $client->getResponseBody(); @@ -65,7 +65,7 @@ class Ajax extends BaseOptions implements ActionInterface 'available' => 1, 'latest' => $json['release'], 'current' => $version, - 'link' => 'http://typecho.org/download' + 'link' => 'https://typecho.org/download' ]; } } @@ -92,7 +92,7 @@ class Ajax extends BaseOptions implements ActionInterface if ($client) { $client->setHeader('User-Agent', $this->options->generator) ->setTimeout(10) - ->send('http://typecho.org/feed/'); + ->send('https://typecho.org/feed/'); /** 匹配内容体 */ $response = $client->getResponseBody(); diff --git a/var/Widget/Archive.php b/var/Widget/Archive.php index 8f3fe825..4d902bc9 100644 --- a/var/Widget/Archive.php +++ b/var/Widget/Archive.php @@ -531,7 +531,7 @@ class Archive extends Contents /** 处理搜索结果跳转 */ if (isset($this->request->s)) { - $filterKeywords = $this->request->filter('search')->s; + $filterKeywords = $this->request->filter('search')->get('s'); /** 跳转到搜索页 */ if (null != $filterKeywords) { diff --git a/var/Widget/Base/Comments.php b/var/Widget/Base/Comments.php index 2a4d0fac..f318711b 100644 --- a/var/Widget/Base/Comments.php +++ b/var/Widget/Base/Comments.php @@ -268,7 +268,7 @@ class Comments extends Base implements QueryInterface $noFollow = (null === $noFollow) ? $this->options->commentsUrlNofollow : $noFollow; if ($this->url && $autoLink) { - echo '' . $this->author . ''; } else { echo $this->author; diff --git a/var/Widget/Feedback.php b/var/Widget/Feedback.php index b8de4c61..cca026df 100644 --- a/var/Widget/Feedback.php +++ b/var/Widget/Feedback.php @@ -206,7 +206,7 @@ class Feedback extends Comments implements ActionInterface /** Anti-XSS */ $comment['author'] = $this->request->filter('trim')->author; $comment['mail'] = $this->request->filter('trim')->mail; - $comment['url'] = $this->request->filter('trim')->url; + $comment['url'] = $this->request->filter('trim', 'url')->url; /** 修正用户提交的url */ if (!empty($comment['url'])) { @@ -305,7 +305,7 @@ class Feedback extends Comments implements ActionInterface ]; $trackback['author'] = $this->request->filter('trim')->blog_name; - $trackback['url'] = $this->request->filter('trim')->url; + $trackback['url'] = $this->request->filter('trim', 'url')->url; $trackback['text'] = $this->request->excerpt; //检验格式 diff --git a/var/Widget/Menu.php b/var/Widget/Menu.php index faf0ab26..e12d6238 100644 --- a/var/Widget/Menu.php +++ b/var/Widget/Menu.php @@ -127,10 +127,10 @@ class Menu extends Base $panelTable = unserialize($this->options->panelTable); $extendingParentMenu = empty($panelTable['parent']) ? [] : $panelTable['parent']; $extendingChildMenu = empty($panelTable['child']) ? [] : $panelTable['child']; - $currentUrl = $this->request->makeUriByRequest(); + $currentUrl = $this->request->getRequestUrl(); $adminUrl = $this->options->adminUrl; $menu = []; - $defaultChildeNode = [null, null, null, 'administrator', false, null]; + $defaultChildNode = [null, null, null, 'administrator', false, null]; $currentUrlParts = parse_url($currentUrl); $currentUrlParams = []; @@ -158,7 +158,7 @@ class Menu extends Base foreach ($childNodes[$key] as $inKey => $childNode) { // magic merge - $childNode += $defaultChildeNode; + $childNode += $defaultChildNode; [$name, $title, $url, $access] = $childNode; $hidden = $childNode[4] ?? false; @@ -255,7 +255,7 @@ class Menu extends Base } $this->menu = $menu; - $this->currentUrl = $currentUrl; + $this->currentUrl = Common::safeUrl($currentUrl); } /** diff --git a/var/Widget/Options.php b/var/Widget/Options.php index 0e5127bb..3dadc434 100644 --- a/var/Widget/Options.php +++ b/var/Widget/Options.php @@ -82,7 +82,7 @@ if (!defined('__TYPECHO_ROOT_DIR__')) { * @property bool $commentsRequireModeration * @property bool $commentsWhitelist * @property bool $commentsRequireMail - * @property bool $commentsRequireURL + * @property bool $commentsRequireUrl * @property bool $commentsCheckReferer * @property bool $commentsAntiSpam * @property bool $commentsAutoClose diff --git a/var/Widget/Options/Discussion.php b/var/Widget/Options/Discussion.php index df9d84c2..d4928f52 100644 --- a/var/Widget/Options/Discussion.php +++ b/var/Widget/Options/Discussion.php @@ -127,7 +127,7 @@ class Discussion extends Options implements ActionInterface $this->options->commentDateFormat, _t('评论日期格式'), _t('这是一个默认的格式,当你在模板中调用显示评论日期方法时, 如果没有指定日期格式, 将按照此格式输出.') . '
' - . _t('具体写法请参考 PHP 日期格式写法.') + . _t('具体写法请参考 PHP 日期格式写法.') ); $commentDateFormat->input->setAttribute('class', 'w-40 mono'); $form->addInput($commentDateFormat); @@ -147,8 +147,8 @@ class Discussion extends Options implements ActionInterface 'commentsShowCommentOnly' => _t('仅显示评论, 不显示 Pingback 和 Trackback'), 'commentsMarkdown' => _t('在评论中使用 Markdown 语法'), 'commentsShowUrl' => _t('评论者名称显示时自动加上其个人主页链接'), - 'commentsUrlNofollow' => _t('对评论者个人主页链接使用 nofollow 属性'), - 'commentsAvatar' => _t('启用 Gravatar 头像服务, 最高显示评级为 %s 的头像', + 'commentsUrlNofollow' => _t('对评论者个人主页链接使用 nofollow 属性'), + 'commentsAvatar' => _t('启用 Gravatar 头像服务, 最高显示评级为 %s 的头像', '