mirror of
https://github.com/typecho/typecho.git
synced 2025-03-19 17:39:42 +01:00
Merge branch 'master' into dev
# Conflicts: # admin/css/style.css # var/Widget/Archive.php
This commit is contained in:
commit
d4a5f765a3
7
.github/workflows/Typecho-dev-Ci.yml
vendored
7
.github/workflows/Typecho-dev-Ci.yml
vendored
@ -55,10 +55,3 @@ jobs:
|
||||
asset_name: typecho.zip
|
||||
asset_content_type: application/zip
|
||||
max_releases: 1
|
||||
- name: Trigger build
|
||||
run: |
|
||||
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.everest-preview+json" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'
|
||||
|
||||
|
6
.github/workflows/Typecho-release-Ci.yml
vendored
6
.github/workflows/Typecho-release-Ci.yml
vendored
@ -37,3 +37,9 @@ jobs:
|
||||
asset_path: ./typecho.zip
|
||||
asset_name: typecho.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Trigger langs build
|
||||
run: |
|
||||
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.everest-preview+json" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'
|
37
CONTRIBUTING.md
Normal file
37
CONTRIBUTING.md
Normal file
@ -0,0 +1,37 @@
|
||||
Contributing to Typecho
|
||||
=======================
|
||||
|
||||
Thanks for considering contributing to Typecho! There are many ways to contribute to Typecho, and we appreciate all of them.
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
If you find a bug in the source code, you can help us by [submitting an issue](https://github.com/typecho/typecho/issues)
|
||||
to our [GitHub Repository](https://github.com/typecho/typecho). Even better, you can submit a Pull Request with a fix.
|
||||
|
||||
## Contributing Code
|
||||
|
||||
If you would like to contribute code to Typecho, please read the following guidelines:
|
||||
|
||||
* [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
* [Contributing Guide](CONTRIBUTING.md)
|
||||
* [Coding Style Guide](CODING_STYLE.md)
|
||||
|
||||
## Translations
|
||||
|
||||
Please see [TRANSLATION](https://github.com/typecho/languages) for details.
|
||||
|
||||
## Plugin Development
|
||||
|
||||
Please see [Plugin Development](http://docs.typecho.org/plugins) for details.
|
||||
|
||||
## Theme Development
|
||||
|
||||
Please see [Theme Development](http://docs.typecho.org/themes) for details.
|
||||
|
||||
## Community
|
||||
|
||||
* [Telegram Channel](https://t.me/typechodev)
|
||||
* [Homepage](http://typecho.org/)
|
||||
* [Documents](http://docs.typecho.org/)
|
||||
* [Community](http://forum.typecho.org/)
|
||||
* [Download](http://typecho.org/download)
|
33
README.md
33
README.md
@ -1,19 +1,30 @@
|
||||
Typecho Blogging Platform
|
||||
=========================
|
||||
|
||||
Typecho is a PHP Blogging Platform. Simple and Powerful.
|
||||
Typecho is a PHP-based blog software and is designed to be the most powerful blog engine in the world.
|
||||
Typecho is released under the GNU General Public License 2.0.
|
||||
|
||||
#### Telegram Channel
|
||||
https://t.me/typechodev
|
||||
## Main Features
|
||||
|
||||
#### Homepage
|
||||
http://typecho.org/
|
||||
* Multiple databases support (MySQL, SQLite, PostgreSQL)
|
||||
* Markdown Support
|
||||
* Plugin Support
|
||||
* Theme Support
|
||||
* Custom Fields
|
||||
* Custom Pages
|
||||
|
||||
#### Documents
|
||||
http://docs.typecho.org/
|
||||
## Requirements
|
||||
|
||||
#### Community
|
||||
http://forum.typecho.org/
|
||||
* PHP 7.2.0 or higher
|
||||
* Database (MySQL, SQLite, PostgreSQL)
|
||||
* MySQL 5.5.3 or higher
|
||||
* SQLite 3.7.11 or higher
|
||||
* PostgreSQL 9.1 or higher
|
||||
|
||||
#### Download
|
||||
http://typecho.org/download
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
|
||||
|
@ -13,7 +13,9 @@
|
||||
noticeType : $.cookie(prefix + '__typecho_notice_type'),
|
||||
highlight : $.cookie(prefix + '__typecho_notice_highlight')
|
||||
},
|
||||
path = '<?php echo \Typecho\Cookie::getPath(); ?>';
|
||||
path = '<?php echo \Typecho\Cookie::getPath(); ?>',
|
||||
domain = '<?php echo \Typecho\Cookie::getDomain(); ?>',
|
||||
secure = <?php echo json_encode(\Typecho\Cookie::getSecure()); ?>;
|
||||
|
||||
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
|
||||
var head = $('.typecho-head-nav'),
|
||||
@ -63,14 +65,13 @@
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$.cookie(prefix + '__typecho_notice', null, {path : path});
|
||||
$.cookie(prefix + '__typecho_notice_type', null, {path : path});
|
||||
$.cookie(prefix + '__typecho_notice', null, {path : path, domain: domain, secure: secure});
|
||||
$.cookie(prefix + '__typecho_notice_type', null, {path : path, domain: domain, secure: secure});
|
||||
}
|
||||
|
||||
if (cookies.highlight) {
|
||||
$('#' + cookies.highlight).effect('highlight', 1000);
|
||||
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path});
|
||||
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path, domain: domain, secure: secure});
|
||||
}
|
||||
})();
|
||||
|
||||
@ -91,6 +92,7 @@
|
||||
|
||||
$('#typecho-nav-list ul.root').each(function () {
|
||||
const ul = $(this), nav = ul.parent();
|
||||
let focused = false;
|
||||
|
||||
ul.on('click touchend', '.parent a', function (e) {
|
||||
nav.removeClass('noexpanded').addClass('expanded');
|
||||
@ -102,6 +104,19 @@
|
||||
nav.removeClass('expanded').addClass('noexpanded');
|
||||
return false;
|
||||
}));
|
||||
|
||||
$('a', ul).focus(function () {
|
||||
ul.addClass('expanded');
|
||||
focused = true;
|
||||
}).blur(function () {
|
||||
focused = false;
|
||||
|
||||
setTimeout(function () {
|
||||
if (!focused) {
|
||||
ul.removeClass('expanded');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if ($('.typecho-login').length == 0) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
|
||||
<?php \Typecho\Plugin::factory('admin/footer.php')->begin(); ?>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
|
@ -279,10 +279,12 @@ $(document).ready(function () {
|
||||
form.submit(function () {
|
||||
var t = $(this), tr = t.parents('tr'),
|
||||
reply = $('<div class="comment-reply-content"></div>').insertAfter($('.comment-content', tr));
|
||||
|
||||
reply.html('<p>' + textarea.val() + '</p>');
|
||||
|
||||
var html = DOMPurify.sanitize(textarea.val(), {USE_PROFILES: {html: true}});
|
||||
reply.html('<p>' + html + '</p>');
|
||||
$.post(t.attr('action'), t.serialize(), function (o) {
|
||||
reply.html(o.comment.content)
|
||||
var html = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
|
||||
reply.html(html)
|
||||
.effect('highlight');
|
||||
}, 'json');
|
||||
|
||||
@ -340,7 +342,7 @@ $(document).ready(function () {
|
||||
}
|
||||
});
|
||||
|
||||
var html = '<strong class="comment-author">'
|
||||
var unsafeHTML = '<strong class="comment-author">'
|
||||
+ (comment.url ? '<a target="_blank" href="' + comment.url + '">'
|
||||
+ comment.author + '</a>' : comment.author) + '</strong>'
|
||||
+ ('comment' != comment.type ? '<small><?php _e('引用'); ?></small>' : '')
|
||||
@ -348,13 +350,16 @@ $(document).ready(function () {
|
||||
+ comment.mail + '</a></span>' : '')
|
||||
+ (comment.ip ? '<br /><span>' + comment.ip + '</span>' : '');
|
||||
|
||||
var html = DOMPurify.sanitize(unsafeHTML, {USE_PROFILES: {html: true}});
|
||||
var content = DOMPurify.sanitize(comment.text, {USE_PROFILES: {html: true}});
|
||||
$('.comment-meta', oldTr).html(html)
|
||||
.effect('highlight');
|
||||
$('.comment-content', oldTr).html('<p>' + comment.text + '</p>');
|
||||
$('.comment-content', oldTr).html('<p>' + content + '</p>');
|
||||
oldTr.data('comment', comment);
|
||||
|
||||
$.post(t.attr('action'), comment, function (o) {
|
||||
$('.comment-content', oldTr).html(o.comment.content)
|
||||
var content = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
|
||||
$('.comment-content', oldTr).html('<p>' + content + '</p>')
|
||||
.effect('highlight');
|
||||
}, 'json');
|
||||
|
||||
|
@ -172,7 +172,7 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="kit-hidden-mb"><a
|
||||
href="<?php $options->adminUrl('manage-posts.php?uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
|
||||
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
|
||||
</td>
|
||||
<td class="kit-hidden-mb"><?php $categories = $posts->categories;
|
||||
$length = count($categories); ?>
|
||||
|
@ -64,7 +64,7 @@ $users = \Widget\Users\Admin::alloc();
|
||||
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $users->uid(); ?>"
|
||||
name="uid[]"/></td>
|
||||
<td class="kit-hidden-mb"><a
|
||||
href="<?php $options->adminUrl('manage-posts.php?uid=' . $users->uid); ?>"
|
||||
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $users->uid); ?>"
|
||||
class="balloon-button left size-<?php echo \Typecho\Common::splitByCount($users->postsNum, 1, 10, 20, 50, 100); ?>"><?php $users->postsNum(); ?></a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -138,7 +138,7 @@ include 'common-js.php';
|
||||
img.get(0).src = '<?php $attachment->attachment->url(); ?>?' + Math.random();
|
||||
}
|
||||
|
||||
$('#' + id).html('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', data.title))
|
||||
$('#' + id).text('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', data.title))
|
||||
.effect('highlight', 1000, function () {
|
||||
$(this).remove();
|
||||
$('#file-list').remove();
|
||||
|
@ -100,7 +100,7 @@ $color-nav-child-focus: #6DA1BB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.root:hover .child {
|
||||
&.root:hover .child, &.root.expanded .child {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
@ -504,6 +504,14 @@ a.operate-reply {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-phone - 1px) {
|
||||
.comment-edit {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 90vw;
|
||||
}
|
||||
.comment-edit td:first-child { display: none; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论回复
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
|
||||
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
|
||||
<script>
|
||||
(function () {
|
||||
$(document).ready(function () {
|
||||
|
@ -16,9 +16,9 @@ include 'menu.php';
|
||||
<li><a class="operate-delete" href="<?php $options->adminUrl('profile.php#change-password'); ?>"><?php _e('强烈建议更改你的默认密码'); ?></a></li>
|
||||
<?php if($user->pass('contributor', true)): ?>
|
||||
<li><a href="<?php $options->adminUrl('write-post.php'); ?>"><?php _e('撰写第一篇日志'); ?></a></li>
|
||||
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
|
||||
<li><a href="<?php $options->siteUrl(); ?>"><?php $user->pass('administrator', true) ? _e('查看我的站点') : _e('查看网站'); ?></a></li>
|
||||
<?php else: ?>
|
||||
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
|
||||
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看网站'); ?></a></li>
|
||||
<?php endif; ?>
|
||||
</ol>
|
||||
<p><button type="submit" class="btn primary"><?php _e('让我直接开始使用吧 »'); ?></button></p>
|
||||
|
@ -281,7 +281,7 @@ $(document).ready(function() {
|
||||
|
||||
var frame = $('<iframe frameborder="0" class="preview-frame preview-loading"></iframe>')
|
||||
.attr('src', './preview.php?cid=' + cid)
|
||||
.attr('sandbox', 'allow-scripts')
|
||||
.attr('sandbox', 'allow-same-origin allow-scripts')
|
||||
.appendTo(document.body);
|
||||
|
||||
frame.load(function () {
|
||||
|
@ -1022,7 +1022,12 @@ function install_step_2_perform()
|
||||
$error = (new \Typecho\Validate())
|
||||
->addRule('dbFile', 'required', _t('确认您的配置'))
|
||||
->addRule('dbFile', function (string $path) {
|
||||
return !!preg_match("/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i", $path);
|
||||
$pattern = "/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
|
||||
if (strstr(PHP_OS, 'WIN'))
|
||||
{
|
||||
$pattern = "/(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
|
||||
}
|
||||
return !!preg_match($pattern, $path);
|
||||
}, _t('确认您的配置'))
|
||||
->run($config);
|
||||
break;
|
||||
|
@ -482,7 +482,7 @@ EOF;
|
||||
*/
|
||||
public static function filterSearchQuery(?string $query): string
|
||||
{
|
||||
return isset($query) ? str_replace('-', ' ', self::slugName($query)) : '';
|
||||
return isset($query) ? str_replace('-', ' ', self::slugName($query) ?? '') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1359,7 +1359,8 @@ EOF;
|
||||
'ice' => 'x-conference/x-cooltalk',
|
||||
'vrm' => 'x-world/x-vrml',
|
||||
'rar' => 'application/x-rar-compressed',
|
||||
'cab' => 'application/vnd.ms-cab-compressed'
|
||||
'cab' => 'application/vnd.ms-cab-compressed',
|
||||
'webp' => 'image/webp'
|
||||
];
|
||||
|
||||
$part = explode('.', $fileName);
|
||||
|
@ -27,6 +27,24 @@ class Cookie
|
||||
*/
|
||||
private static $path = '/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private static $domain = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
private static $secure = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
private static $httponly = false;
|
||||
|
||||
/**
|
||||
* 获取前缀
|
||||
*
|
||||
@ -51,6 +69,7 @@ class Cookie
|
||||
self::$prefix = md5($url);
|
||||
$parsed = parse_url($url);
|
||||
|
||||
self::$domain = $parsed['host'];
|
||||
/** 在路径后面强制加上斜杠 */
|
||||
self::$path = empty($parsed['path']) ? '/' : Common::url(null, $parsed['path']);
|
||||
}
|
||||
@ -66,6 +85,37 @@ class Cookie
|
||||
return self::$path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public static function getDomain(): string
|
||||
{
|
||||
return self::$domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public static function getSecure(): bool
|
||||
{
|
||||
return self::$secure ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置额外的选项
|
||||
*
|
||||
* @param array $options
|
||||
* @return void
|
||||
*/
|
||||
public static function setOptions(array $options)
|
||||
{
|
||||
self::$domain = $options['domain'] ?: self::$domain;
|
||||
self::$secure = $options['secure'] ? (bool) $options['secure'] : false;
|
||||
self::$httponly = $options['httponly'] ? (bool) $options['httponly'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的COOKIE值
|
||||
*
|
||||
@ -91,7 +141,7 @@ class Cookie
|
||||
{
|
||||
$key = self::$prefix . $key;
|
||||
$_COOKIE[$key] = $value;
|
||||
Response::getInstance()->setCookie($key, $value, $expire, self::$path);
|
||||
Response::getInstance()->setCookie($key, $value, $expire, self::$path, self::$domain, self::$secure, self::$httponly);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +156,7 @@ class Cookie
|
||||
return;
|
||||
}
|
||||
|
||||
Response::getInstance()->setCookie($key, '', -1, self::$path);
|
||||
Response::getInstance()->setCookie($key, '', -1, self::$path, self::$domain, self::$secure, self::$httponly);
|
||||
unset($_COOKIE[$key]);
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ xmlns:dc="http://purl.org/dc/elements/1.1/">' . self::EOL;
|
||||
$result .= '<channel rdf:about="' . $this->feedUrl . '">
|
||||
<title>' . htmlspecialchars($this->title) . '</title>
|
||||
<link>' . $this->baseUrl . '</link>
|
||||
<description>' . htmlspecialchars($this->subTitle) . '</description>
|
||||
<description>' . htmlspecialchars($this->subTitle ?? '') . '</description>
|
||||
<items>
|
||||
<rdf:Seq>' . self::EOL;
|
||||
|
||||
@ -310,7 +310,7 @@ xmlns:wfw="http://wellformedweb.org/CommentAPI/">
|
||||
<link>' . $this->baseUrl . '</link>
|
||||
<atom:link href="' . $this->feedUrl . '" rel="self" type="application/rss+xml" />
|
||||
<language>' . $this->lang . '</language>
|
||||
<description>' . htmlspecialchars($this->subTitle) . '</description>
|
||||
<description>' . htmlspecialchars($this->subTitle ?? '') . '</description>
|
||||
<lastBuildDate>' . $this->dateFormat($lastUpdate) . '</lastBuildDate>
|
||||
<pubDate>' . $this->dateFormat($lastUpdate) . '</pubDate>' . self::EOL;
|
||||
|
||||
@ -380,7 +380,7 @@ xml:base="' . $this->baseUrl . '"
|
||||
}
|
||||
|
||||
$result .= '<title type="text">' . htmlspecialchars($this->title) . '</title>
|
||||
<subtitle type="text">' . htmlspecialchars($this->subTitle) . '</subtitle>
|
||||
<subtitle type="text">' . htmlspecialchars($this->subTitle ?? '') . '</subtitle>
|
||||
<updated>' . $this->dateFormat($lastUpdate) . '</updated>
|
||||
<generator uri="http://typecho.org/" version="' . $this->version . '">Typecho</generator>
|
||||
<link rel="alternate" type="text/html" href="' . $this->baseUrl . '" />
|
||||
|
@ -430,6 +430,7 @@ class Request
|
||||
public function isSecure(): bool
|
||||
{
|
||||
return (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && !strcasecmp('https', $_SERVER['HTTP_X_FORWARDED_PROTO']))
|
||||
|| (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && !strcasecmp('quic', $_SERVER['HTTP_X_FORWARDED_PROTO']))
|
||||
|| (!empty($_SERVER['HTTP_X_FORWARDED_PORT']) && 443 == $_SERVER['HTTP_X_FORWARDED_PORT'])
|
||||
|| (!empty($_SERVER['HTTPS']) && 'off' != strtolower($_SERVER['HTTPS']))
|
||||
|| (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT'])
|
||||
|
@ -200,7 +200,7 @@ class Response
|
||||
|
||||
// set cookie
|
||||
foreach ($this->cookies as $cookie) {
|
||||
[$key, $value, $timeout, $path, $domain] = $cookie;
|
||||
[$key, $value, $timeout, $path, $domain, $secure, $httponly] = $cookie;
|
||||
|
||||
if ($timeout > 0) {
|
||||
$now = time();
|
||||
@ -209,7 +209,7 @@ class Response
|
||||
$timeout = 1;
|
||||
}
|
||||
|
||||
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain ?? '');
|
||||
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain, $secure, $httponly);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,6 +275,8 @@ class Response
|
||||
* @param integer $timeout 过期时间,默认为0,表示随会话时间结束
|
||||
* @param string $path 路径信息
|
||||
* @param string|null $domain 域名信息
|
||||
* @param bool $secure 是否仅可通过安全的 HTTPS 连接传给客户端
|
||||
* @param bool $httponly 是否仅可通过 HTTP 协议访问
|
||||
* @return $this
|
||||
*/
|
||||
public function setCookie(
|
||||
@ -282,10 +284,12 @@ class Response
|
||||
$value,
|
||||
int $timeout = 0,
|
||||
string $path = '/',
|
||||
string $domain = null
|
||||
string $domain = '',
|
||||
bool $secure = false,
|
||||
bool $httponly = false
|
||||
): Response {
|
||||
if (!$this->sandbox) {
|
||||
$this->cookies[] = [$key, $value, $timeout, $path, $domain];
|
||||
$this->cookies[] = [$key, $value, $timeout, $path, $domain, $secure, $httponly];
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Typecho\Widget\Helper;
|
||||
|
||||
use Typecho\Cookie;
|
||||
use Typecho\Request;
|
||||
use Typecho\Validate;
|
||||
use Typecho\Widget\Helper\Form\Element;
|
||||
|
||||
@ -130,13 +131,7 @@ class Form extends Layout
|
||||
*/
|
||||
public function getAllRequest(): array
|
||||
{
|
||||
$result = [];
|
||||
$source = (self::POST_METHOD == $this->getAttribute('method')) ? $_POST : $_GET;
|
||||
|
||||
foreach ($this->inputs as $name => $input) {
|
||||
$result[$name] = $source[$name] ?? null;
|
||||
}
|
||||
return $result;
|
||||
return $this->getParams(array_keys($this->inputs));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,10 +199,10 @@ class Form extends Layout
|
||||
public function getParams(array $params): array
|
||||
{
|
||||
$result = [];
|
||||
$source = (self::POST_METHOD == $this->getAttribute('method')) ? $_POST : $_GET;
|
||||
$request = Request::getInstance();
|
||||
|
||||
foreach ($params as $param) {
|
||||
$result[$param] = $source[$param] ?? null;
|
||||
$result[$param] = $request->get($param, is_array($this->getInput($param)->value) ? [] : null);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -59,7 +59,7 @@ class Helper
|
||||
|
||||
$key = $keys[$table];
|
||||
$db = Db::get();
|
||||
$widget = Widget::widget($className);
|
||||
$widget = Widget::widget($className . '@' . $pkId);
|
||||
|
||||
$db->fetchRow(
|
||||
$widget->select()->where("{$key} = ?", $pkId)->limit(1),
|
||||
|
@ -943,8 +943,8 @@ class Archive extends Contents
|
||||
{
|
||||
$rules = [];
|
||||
$allows = [
|
||||
'description' => htmlspecialchars($this->description),
|
||||
'keywords' => htmlspecialchars($this->keywords),
|
||||
'description' => htmlspecialchars($this->description ?? ''),
|
||||
'keywords' => htmlspecialchars($this->keywords ?? ''),
|
||||
'generator' => $this->options->generator,
|
||||
'template' => $this->options->theme,
|
||||
'pingback' => $this->options->xmlRpcUrl,
|
||||
@ -1209,7 +1209,7 @@ class Archive extends Contents
|
||||
*/
|
||||
public function keywords(string $split = ',', string $default = '')
|
||||
{
|
||||
echo empty($this->keywords) ? $default : str_replace(',', $split, htmlspecialchars($this->keywords));
|
||||
echo empty($this->keywords) ? $default : str_replace(',', $split, htmlspecialchars($this->keywords ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,7 +189,12 @@ class Backup extends BaseOptions implements ActionInterface
|
||||
if (!empty($_FILES)) {
|
||||
$file = array_pop($_FILES);
|
||||
|
||||
if (0 == $file['error'] && is_uploaded_file($file['tmp_name'])) {
|
||||
if(UPLOAD_ERR_NO_FILE == $file['error']) {
|
||||
Notice::alloc()->set(_t('没有选择任何备份文件'), 'error');
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
if (UPLOAD_ERR_OK == $file['error'] && is_uploaded_file($file['tmp_name'])) {
|
||||
$path = $file['tmp_name'];
|
||||
} else {
|
||||
Notice::alloc()->set(_t('备份文件上传失败'), 'error');
|
||||
@ -270,7 +275,7 @@ class Backup extends BaseOptions implements ActionInterface
|
||||
}
|
||||
|
||||
// 针对PGSQL重置计数
|
||||
if (false !== strpos($this->db->getVersion(), 'pgsql')) {
|
||||
if (false !== strpos(strtolower($this->db->getAdapterName()), 'pgsql')) {
|
||||
foreach ($this->lastIds as $table => $id) {
|
||||
$seq = $this->db->getPrefix() . $table . '_seq';
|
||||
$this->db->query('ALTER SEQUENCE ' . $seq . ' RESTART WITH ' . ($id + 1));
|
||||
|
@ -289,7 +289,7 @@ class Comments extends Base implements QueryInterface
|
||||
Comments::pluginHandle()->trigger($plugged)->gravatar($size, $rating, $default, $this);
|
||||
if (!$plugged) {
|
||||
$url = Common::gravatarUrl($this->mail, $size, $rating, $default, $this->request->isSecure());
|
||||
echo '<img class="avatar" src="' . $url . '" alt="' .
|
||||
echo '<img class="avatar" loading="lazy" src="' . $url . '" alt="' .
|
||||
$this->author . '" width="' . $size . '" height="' . $size . '" />';
|
||||
}
|
||||
}
|
||||
|
@ -555,7 +555,7 @@ class Contents extends Base implements QueryInterface
|
||||
|
||||
//增加数据信息
|
||||
$value['attachment'] = new Config($content);
|
||||
$value['attachment']->isImage = in_array($content['type'], ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp']);
|
||||
$value['attachment']->isImage = in_array($content['type'], ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp', 'webp', 'avif']);
|
||||
$value['attachment']->url = Upload::attachmentHandle($value);
|
||||
|
||||
if ($value['attachment']->isImage) {
|
||||
@ -940,7 +940,7 @@ class Contents extends Base implements QueryInterface
|
||||
{
|
||||
$html = Contents::pluginHandle()->trigger($parsed)->autoP($text);
|
||||
|
||||
if (!$parsed) {
|
||||
if (!$parsed && $text) {
|
||||
static $parser;
|
||||
|
||||
if (empty($parser)) {
|
||||
|
@ -405,7 +405,7 @@ class Edit extends Contents implements ActionInterface
|
||||
$realId = 0;
|
||||
|
||||
/** 是否是从草稿状态发布 */
|
||||
$isDraftToPublish = ('post_draft' == $this->type);
|
||||
$isDraftToPublish = ('post_draft' == $this->type || 'page_draft' == $this->type);
|
||||
|
||||
$isBeforePublish = ('publish' == $this->status);
|
||||
$isAfterPublish = ('publish' == $contents['status']);
|
||||
|
@ -93,7 +93,10 @@ class Init extends Widget
|
||||
}
|
||||
|
||||
/** cookie初始化 */
|
||||
Cookie::setPrefix($options->rootUrl);
|
||||
Cookie::setPrefix($options->rootUrl);
|
||||
if (defined('__TYPECHO_COOKIE_OPTIONS__')) {
|
||||
Cookie::setOptions(__TYPECHO_COOKIE_OPTIONS__);
|
||||
}
|
||||
|
||||
/** 初始化路由器 */
|
||||
Router::setRoutes($options->routingTable);
|
||||
|
@ -261,18 +261,18 @@ class Options extends Base
|
||||
*
|
||||
* @param string|null $path 子路径
|
||||
* @param string|null $theme 模版名称
|
||||
* @return string
|
||||
* @return string | void
|
||||
*/
|
||||
public function themeUrl(?string $path = null, ?string $theme = null): string
|
||||
public function themeUrl(?string $path = null, ?string $theme = null)
|
||||
{
|
||||
if (empty($theme)) {
|
||||
if (!isset($theme)) {
|
||||
echo Common::url($path, $this->themeUrl);
|
||||
} else {
|
||||
$url = defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
|
||||
Common::url(__TYPECHO_THEME_DIR__ . '/' . $theme, $this->siteUrl);
|
||||
|
||||
return isset($path) ? Common::url($path, $url) : $url;
|
||||
}
|
||||
|
||||
$url = defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
|
||||
Common::url(__TYPECHO_THEME_DIR__ . '/' . $theme, $this->siteUrl);
|
||||
|
||||
return Common::url($path, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -482,8 +482,7 @@ class Options extends Base
|
||||
*/
|
||||
protected function ___themeUrl(): string
|
||||
{
|
||||
return defined('__TYPECHO_THEME_URL__') ? __TYPECHO_THEME_URL__ :
|
||||
Common::url(__TYPECHO_THEME_DIR__ . '/' . $this->theme, $this->siteUrl);
|
||||
return $this->themeUrl(null, $this->theme);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -671,7 +670,7 @@ class Options extends Base
|
||||
$attachmentTypes = str_replace(
|
||||
['@image@', '@media@', '@doc@'],
|
||||
[
|
||||
'gif,jpg,jpeg,png,tiff,bmp', 'mp3,mp4,mov,wmv,wma,rmvb,rm,avi,flv,ogg,oga,ogv',
|
||||
'gif,jpg,jpeg,png,tiff,bmp,webp', 'mp3,mp4,mov,wmv,wma,rmvb,rm,avi,flv,ogg,oga,ogv',
|
||||
'txt,doc,docx,xls,xlsx,ppt,pptx,zip,rar,pdf'
|
||||
],
|
||||
$this->attachmentTypes
|
||||
|
@ -272,7 +272,7 @@ class General extends Options implements ActionInterface
|
||||
}
|
||||
|
||||
$attachmentTypesOptions = [
|
||||
'@image@' => _t('图片文件') . ' <code>(gif jpg jpeg png tiff bmp)</code>',
|
||||
'@image@' => _t('图片文件') . ' <code>(gif jpg jpeg png tiff bmp webp avif)</code>',
|
||||
'@media@' => _t('多媒体文件') . ' <code>(mp3 mp4 mov wmv wma rmvb rm avi flv ogg oga ogv)</code>',
|
||||
'@doc@' => _t('常用档案文件') . ' <code>(txt doc docx xls xlsx ppt pptx zip rar pdf)</code>',
|
||||
'@other@' => _t(
|
||||
|
@ -238,7 +238,7 @@ class Stat extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户显示的评论数目
|
||||
* 获取当前用户待审核的评论数目
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
@ -251,7 +251,7 @@ class Stat extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户显示的评论数目
|
||||
* 获取当前用户垃圾评论数目
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
@ -289,7 +289,7 @@ class Stat extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前文章显示的评论数目
|
||||
* 获取当前文章待审核的评论数目
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
@ -302,7 +302,7 @@ class Stat extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前文章显示的评论数目
|
||||
* 获取当前文章垃圾评论数目
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
|
@ -46,6 +46,8 @@ class Edit extends Options implements ActionInterface
|
||||
$this->update(['value' => 'recent'], $this->db->sql()->where('name = ?', 'frontPage'));
|
||||
}
|
||||
|
||||
$this->options->themeUrl = $this->options->themeUrl(null, $theme);
|
||||
|
||||
$configFile = $this->options->themeFile($theme, 'functions.php');
|
||||
|
||||
if (file_exists($configFile)) {
|
||||
|
@ -45,7 +45,7 @@ class Rows extends Widget
|
||||
}
|
||||
|
||||
$screen = array_filter(glob($theme . '/*'), function ($path) {
|
||||
return preg_match("/screenshot\.(jpg|png|gif|bmp|jpeg)$/i", $path);
|
||||
return preg_match("/screenshot\.(jpg|png|gif|bmp|jpeg|webp|avif)$/i", $path);
|
||||
});
|
||||
|
||||
if ($screen) {
|
||||
|
@ -463,7 +463,6 @@ class XmlRpc extends Contents implements ActionInterface, Hook
|
||||
*/
|
||||
public function wpNewCategory(int $blogId, string $userName, string $password, array $category): int
|
||||
{
|
||||
|
||||
/** 开始接受数据 */
|
||||
$input['name'] = $category['name'];
|
||||
$input['slug'] = Common::slugName(empty($category['slug']) ? $category['name'] : $category['slug']);
|
||||
@ -474,6 +473,11 @@ class XmlRpc extends Contents implements ActionInterface, Hook
|
||||
$categoryWidget = CategoryEdit::alloc(null, $input, function (CategoryEdit $category) {
|
||||
$category->insertCategory();
|
||||
});
|
||||
|
||||
if (!$categoryWidget->have()) {
|
||||
throw new Exception(_t('分类不存在'), 404);
|
||||
}
|
||||
|
||||
return $categoryWidget->mid;
|
||||
}
|
||||
|
||||
@ -1833,7 +1837,7 @@ EOF;
|
||||
'wp.suggestCategories' => [$this, 'wpSuggestCategories'],
|
||||
'wp.uploadFile' => [$this, 'mwNewMediaObject'],
|
||||
|
||||
/** New Wordpress API since 2.9.2 */
|
||||
/** New WordPress API since 2.9.2 */
|
||||
'wp.getUsersBlogs' => [$this, 'wpGetUsersBlogs'],
|
||||
'wp.getTags' => [$this, 'wpGetTags'],
|
||||
'wp.deleteCategory' => [$this, 'wpDeleteCategory'],
|
||||
|
Loading…
x
Reference in New Issue
Block a user