40 Commits

Author SHA1 Message Date
沈唁
4be93f2741 Fix missing mysqli_connect_errno (#1346) 2022-03-28 12:11:24 +08:00
joyqi
6100695d87 fix db exception 2022-03-25 15:31:57 +08:00
fen
0bdf8721e1 add ignore 2022-03-25 12:08:22 +08:00
沈唁
ce7af58367 Optimize code (#1342) 2022-03-24 17:46:03 +08:00
joyqi
1b673e06ff fix typecho/Dockerfile#9 2022-03-22 14:24:14 +08:00
joyqi
0edb48fae0 fix #1335, close #1337 2022-03-16 21:05:22 +08:00
沈唁
17fcb2f08b Fix undefined Typecho\Db\Adapter_Exception (#1334) 2022-03-15 16:09:32 +08:00
joyqi
5f943d48b5 fix #1329 2022-02-25 21:16:12 +08:00
joyqi
b23277267a fix #1328 2022-02-24 23:21:35 +08:00
沈唁
b0d78a81dc Fix #1326 (#1327) 2022-02-21 21:51:13 +08:00
沈唁
f34d14280d Fix compatibility with PHP 8.1 (#1324)
* Fix compatibility with PHP 8.1

PHP Deprecated:  htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in typecho/var/Widget/Archive.php on line 1292

* Fix login

* Fix write

* Fix manage

* Fix PHP Deprecated
2022-02-15 11:10:47 +08:00
沈唁
13dc5e87dd Fix #1322 (#1323)
Great work!
2022-02-15 11:10:15 +08:00
沈唁
0b021e5e7d Fix broken extends.typecho.org link (#1315)
close #857
2022-02-09 11:41:35 +08:00
joyqi
00c75d2f75 fix version compare 2022-01-30 00:30:28 +08:00
joyqi
1eedc481ad fix #1295, ref #1297 2022-01-29 17:46:48 +08:00
joyqi
75899e287d fix #1268 2022-01-28 23:58:31 +08:00
jiayx
047bd17f19 Fixes for PHP 8.1 compatibility (#1293)
* Fixes for PHP 8.1 compatibility

* Fixes for PHP 8.1 compatibility

* 优化写法

* remove mixed type

* fix nullable column

* fix query filter

* recover

* recover fileds

* recover

* Update Text.php

* Update Text.php

Co-authored-by: joyqi <joyqi@users.noreply.github.com>
2022-01-28 23:51:24 +08:00
joyqi
9c075dcdf0 fix #1279 2022-01-13 14:04:58 +08:00
joyqi
157fc05265 fix #1268 2021-12-13 11:58:35 +08:00
joyqi
c047669900 fix #1257 2021-12-06 22:09:17 +08:00
joyqi
eee0228fed Refactor HttpClient, fix #1246 2021-11-18 00:20:24 +08:00
joyqi
389b46635e fix client 2021-11-17 18:34:01 +08:00
joyqi
919911e288 fix redirect 2021-11-17 00:33:05 +08:00
joyqi
dd4bf889de fix #1222 2021-11-04 16:37:29 +08:00
joyqi
0dcf45a152 fix #1220 2021-10-30 00:02:41 +08:00
joyqi
ceaa545c7d fix #1212 2021-10-28 19:53:18 +08:00
joyqi
01d9d0c3f5 fix #1207 2021-10-28 12:04:00 +08:00
joyqi
6b46dd9c50 Merge branch 'master' of github.com:typecho/typecho 2021-10-21 22:09:05 +08:00
joyqi
cb4457ab52 fix #1201 2021-10-21 22:08:53 +08:00
joyqi
8a57b91343 fix #1203 2021-10-21 18:49:05 +08:00
joyqi
c66b6e20ec fix #1187 2021-10-21 11:10:34 +08:00
joyqi
b33a9c4d02 ref https://github.com/typecho/Dockerfile/issues/1 2021-10-13 18:34:46 +08:00
joyqi
cac1c650a1 fix #1196 2021-10-13 16:31:15 +08:00
joyqi
42e192340d fix #1194 2021-10-13 15:50:40 +08:00
joyqi
b677f7db92 Merge branch 'master' of github.com:typecho/typecho 2021-10-13 14:33:43 +08:00
joyqi
2fbc56dead ref https://github.com/typecho/Dockerfile/issues/1 2021-10-13 14:33:28 +08:00
joyqi
d174cc5732 update hyperdown 2021-09-30 01:06:14 +08:00
joyqi
5557f6dd91 fix clear 2021-09-29 17:10:34 +08:00
joyqi
42fe6f7bf5 fix #1191 2021-09-26 16:15:17 +08:00
joyqi
1f1019ba5b fix #1189 2021-09-23 11:29:10 +08:00
58 changed files with 664 additions and 895 deletions

View File

@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: ['7.2', '7.3', '7.4', '8.0']
php: ['7.2', '7.3', '7.4', '8.0', '8.1']
steps:
- name: Checkout code
uses: actions/checkout@v2

1
.gitignore vendored
View File

@@ -24,6 +24,7 @@
*.sublime*
.sass-cache
config.rb
prepros.config
/config.inc.php
/usr/uploads/
/usr/*.db

View File

@@ -8,6 +8,6 @@
<a href="http://docs.typecho.org"><?php _e('帮助文档'); ?></a> &bull;
<a href="http://forum.typecho.org"><?php _e('支持论坛'); ?></a> &bull;
<a href="https://github.com/typecho/typecho/issues"><?php _e('报告错误'); ?></a> &bull;
<a href="http://extends.typecho.org"><?php _e('资源下载'); ?></a>
<a href="http://typecho.org/download"><?php _e('资源下载'); ?></a>
</nav>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@ include 'common.php';
if ($user->hasLogin()) {
$response->redirect($options->adminUrl);
}
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name'));
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name', ''));
\Typecho\Cookie::delete('__typecho_remember_name');
$bodyClass = 'body-100';
@@ -25,10 +25,12 @@ include 'header.php';
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('登录'); ?></button>
<input type="hidden" name="referer" value="<?php echo htmlspecialchars($request->get('referer')); ?>" />
<input type="hidden" name="referer" value="<?php echo htmlspecialchars($request->get('referer') ?? ''); ?>" />
</p>
<p>
<label for="remember"><input type="checkbox" name="remember" class="checkbox" value="1" id="remember" /> <?php _e('下次自动登录'); ?></label>
<label for="remember">
<input<?php if(\Typecho\Cookie::get('__typecho_remember_remember')): ?> checked<?php endif; ?> type="checkbox" name="remember" class="checkbox" value="1" id="remember" /> <?php _e('下次自动登录'); ?>
</label>
</p>
</form>

View File

@@ -69,7 +69,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
(isset($request->status) ? 'status=' . htmlspecialchars($request->get('status')) : '') .
(isset($request->cid) ? (isset($request->status) ? '&' : '') . 'cid=' . htmlspecialchars($request->get('cid')) : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>" value="<?php echo htmlspecialchars($request->keywords); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>" value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<?php if(isset($request->status)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('status')); ?>" name="status" />
<?php endif; ?>

View File

@@ -36,7 +36,7 @@ $attachments = \Widget\Contents\Attachment\Admin::alloc();
<a href="<?php $options->adminUrl('manage-medias.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>

View File

@@ -39,7 +39,7 @@ $pages = \Widget\Contents\Page\Admin::alloc();
<a href="<?php $options->adminUrl('manage-pages.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords); ?>" name="keywords"/>
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>

View File

@@ -16,10 +16,10 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<ul class="typecho-option-tabs right">
<?php if ($user->pass('editor', true) && !isset($request->uid)): ?>
<li class="<?php if ($isAllPosts): ?> current<?php endif; ?>"><a
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=on'); ?>"><?php _e('所有'); ?></a>
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=on&page=1'); ?>"><?php _e('所有'); ?></a>
</li>
<li class="<?php if (!$isAllPosts): ?> current<?php endif; ?>"><a
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=off'); ?>"><?php _e('我的'); ?></a>
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=off&page=1'); ?>"><?php _e('我的'); ?></a>
</li>
<?php endif; ?>
</ul>
@@ -91,7 +91,7 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
(isset($request->uid) ? '?uid=' . htmlspecialchars($request->get('uid')) : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords); ?>" name="keywords"/>
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
<select name="category">
<option value=""><?php _e('所有分类'); ?></option>
<?php \Widget\Metas\Category\Rows::alloc()->to($category); ?>

View File

@@ -31,7 +31,7 @@ $users = \Widget\Users\Admin::alloc();
<a href="<?php $options->adminUrl('manage-users.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords); ?>" name="keywords"/>
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>

View File

@@ -11,7 +11,7 @@ $stat = \Widget\Stat::alloc();
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-3">
<p><a href="http://gravatar.com/emails/"
<p><a href="https://gravatar.com/emails/"
title="<?php _e('在 Gravatar 上修改头像'); ?>"><?php echo '<img class="profile-avatar" src="' . \Typecho\Common::gravatarUrl($user->mail, 220, 'X', 'mm', $request->isSecure()) . '" alt="' . $user->screenName . '" />'; ?></a>
</p>
<h2><?php $user->screenName(); ?></h2>

View File

@@ -819,7 +819,7 @@
}
parseList(lines, value, start) {
var html, j, key, l, last, len, len1, line, matches, row, rows, space, suffix, tab, type;
var html, j, key, l, last, len, len1, line, matches, olStart, row, rows, space, suffix, tab, type;
html = '';
[space, type, tab] = value;
rows = [];
@@ -829,9 +829,9 @@
line = lines[key];
if (matches = line.match(new RegExp(`^(\\s{${space}})((?:[0-9]+\\.?)|\\-|\\+|\\*)(\\s+)(.*)$`))) {
if (type === 'ol' && key === 0) {
start = parseInt(matches[2]);
if (start !== 1) {
suffix = ' start="' + start + '"';
olStart = parseInt(matches[2]);
if (olStart !== 1) {
suffix = ' start="' + olStart + '"';
}
}
rows.push([matches[4]]);

View File

@@ -34,7 +34,7 @@ include 'menu.php';
if ($page->have()) {
$permalink = str_replace('{cid}', $page->cid, $permalink);
}
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($page->slug) . '" class="mono" />';
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($page->slug ?? '') . '" class="mono" />';
?>
<p class="mono url-slug">
<label for="slug" class="sr-only"><?php _e('网址缩略名'); ?></label>
@@ -43,7 +43,7 @@ include 'menu.php';
<p>
<label for="text" class="sr-only"><?php _e('页面内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($page->text); ?></textarea>
name="text" class="w-100 mono"><?php echo htmlspecialchars($page->text ?? ''); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>

View File

@@ -38,7 +38,7 @@ include 'menu.php';
$post->cid, $post->category, $post->year, $post->month, $post->day
], $permalink);
}
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($post->slug) . '" class="mono" />';
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($post->slug ?? '') . '" class="mono" />';
?>
<p class="mono url-slug">
<label for="slug" class="sr-only"><?php _e('网址缩略名'); ?></label>
@@ -47,7 +47,7 @@ include 'menu.php';
<p>
<label for="text" class="sr-only"><?php _e('文章内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text); ?></textarea>
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text ?? ''); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>
@@ -134,7 +134,7 @@ include 'menu.php';
<option
value="hidden"<?php if ($post->status == 'hidden'): ?> selected<?php endif; ?>><?php _e('隐藏'); ?></option>
<option
value="password"<?php if (strlen($post->password) > 0): ?> selected<?php endif; ?>><?php _e('密码保护'); ?></option>
value="password"<?php if (strlen($post->password ?? '') > 0): ?> selected<?php endif; ?>><?php _e('密码保护'); ?></option>
<option
value="private"<?php if ($post->status == 'private'): ?> selected<?php endif; ?>><?php _e('私密'); ?></option>
<?php endif; ?>
@@ -142,7 +142,7 @@ include 'menu.php';
value="waiting"<?php if (!$user->pass('editor', true) || $post->status == 'waiting'): ?> selected<?php endif; ?>><?php _e('待审核'); ?></option>
</select>
</p>
<p id="post-password"<?php if (strlen($post->password) == 0): ?> class="hidden"<?php endif; ?>>
<p id="post-password"<?php if (strlen($post->password ?? '') == 0): ?> class="hidden"<?php endif; ?>>
<label for="protect-pwd" class="sr-only">内容密码</label>
<input type="text" name="password" id="protect-pwd" class="text-s"
value="<?php $post->password(); ?>" size="16"

View File

@@ -54,7 +54,8 @@ function install_get_lang(): string
*/
function install_get_site_url(): string
{
return install_is_cli() ? 'http://localhost' : \Typecho\Request::getInstance()->getRequestRoot();
$request = \Typecho\Request::getInstance();
return install_is_cli() ? $request->getServer('TYPECHO_SITE_URL', 'http://localhost') : $request->getRequestRoot();
}
/**
@@ -508,7 +509,13 @@ function install_raise_error($error, $config = null)
*/
function install_success($step, ?array $config = null)
{
global $installDb;
if (install_is_cli()) {
if ($step == 3) {
\Typecho\Db::set($installDb);
}
if ($step > 0) {
$method = 'install_step_' . $step . '_perform';
$method();
@@ -1014,6 +1021,9 @@ function install_step_2_perform()
case 'SQLite':
$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);
}, _t('确认您的配置'))
->run($config);
break;
default:
@@ -1034,6 +1044,10 @@ function install_step_2_perform()
$dbConfig['port'] = intval($dbConfig['port']);
}
if (isset($dbConfig['file']) && preg_match("/^[a-z0-9]+\.[a-z0-9]{2,}$/i", $dbConfig['file'])) {
$dbConfig['file'] = __DIR__ . '/usr/' . $dbConfig['file'];
}
// check config file
if ($config['dbNext'] == 'config' && !install_check('config')) {
$code = install_config_file($config['dbAdapter'], $config['dbPrefix'], $dbConfig, true);
@@ -1044,10 +1058,10 @@ function install_step_2_perform()
$installDb = new \Typecho\Db($config['dbAdapter'], $config['dbPrefix']);
$installDb->addServer($dbConfig, \Typecho\Db::READ | \Typecho\Db::WRITE);
$installDb->query('SELECT 1=1');
} catch (\Typecho\Db\Adapter_Exception $e) {
} catch (\Typecho\Db\Adapter\ConnectionException $e) {
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装'));
} catch (\Typecho\Db\Exception $e) {
install_raise_error(_t('安装程序捕捉到以下错误: " %s ". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
}
$code = install_config_file($config['dbAdapter'], $config['dbPrefix'], $dbConfig);
@@ -1077,12 +1091,14 @@ function install_step_2_perform()
try {
foreach ($tables as $table) {
if ($type == 'Mysql') {
$installDb->query("DROP TABLE IF EXISTS `{$table}`");
} elseif ($type == 'Pgsql') {
$installDb->query("DROP TABLE {$table}");
} elseif ($type == 'SQLite') {
$installDb->query("DROP TABLE {$table}");
switch ($type) {
case 'Mysql':
$installDb->query("DROP TABLE IF EXISTS `{$table}`");
break;
case 'Pgsql':
case 'SQLite':
$installDb->query("DROP TABLE {$table}");
break;
}
}
} catch (\Typecho\Db\Exception $e) {
@@ -1314,7 +1330,7 @@ function install_step_3_perform()
'cid' => 1, 'created' => \Typecho\Date::time(),
'author' => 'Typecho',
'ownerId' => 1,
'url' => 'http://typecho.org',
'url' => 'https://typecho.org',
'ip' => '127.0.0.1',
'agent' => $options->generator,
'text' => '欢迎加入 Typecho 大家族',

View File

@@ -40,7 +40,6 @@ class Server
$this->setCapabilities();
$this->callbacks = $callbacks;
$this->setCallbacks();
$this->serve();
}
/**
@@ -298,7 +297,7 @@ class Server
/**
* 服务入口
*/
private function serve()
public function serve()
{
$message = new Message(file_get_contents('php://input') ?: '');

View File

@@ -182,8 +182,10 @@ namespace Typecho {
*/
public static function url(?string $path, ?string $prefix): string
{
$path = $path ?? '';
$path = (0 === strpos($path, './')) ? substr($path, 2) : $path;
return rtrim($prefix, '/') . '/' . str_replace('//', '/', ltrim($path, '/'));
return rtrim($prefix ?? '', '/') . '/'
. str_replace('//', '/', ltrim($path, '/'));
}
/**
@@ -228,10 +230,10 @@ namespace Typecho {
//覆盖原始错误信息
$message = 'Database Server Error';
if ($exception instanceof \Typecho\Db\Adapter\SQLException) {
if ($exception instanceof \Typecho\Db\Adapter\ConnectionException) {
$code = 503;
$message = 'Error establishing a database connection';
} elseif ($exception instanceof \Typecho\Db\Query\Exception) {
} elseif ($exception instanceof \Typecho\Db\Adapter\SQLException) {
$message = 'Database Query Error';
}
}
@@ -480,7 +482,7 @@ EOF;
*/
public static function filterSearchQuery(?string $query): string
{
return str_replace('-', ' ', self::slugName($query));
return isset($query) ? str_replace('-', ' ', self::slugName($query)) : '';
}
/**
@@ -496,7 +498,7 @@ EOF;
*/
public static function slugName(?string $str, ?string $default = null, int $maxLength = 128): ?string
{
$str = trim($str);
$str = trim($str ?? '');
if (!strlen($str)) {
return $default;

View File

@@ -91,7 +91,7 @@ class Config implements \Iterator, \ArrayAccess
* @access public
* @return void
*/
public function rewind()
public function rewind(): void
{
reset($this->currentConfig);
}
@@ -102,6 +102,7 @@ class Config implements \Iterator, \ArrayAccess
* @access public
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
{
return current($this->currentConfig);
@@ -113,7 +114,7 @@ class Config implements \Iterator, \ArrayAccess
* @access public
* @return void
*/
public function next()
public function next(): void
{
next($this->currentConfig);
}
@@ -124,6 +125,7 @@ class Config implements \Iterator, \ArrayAccess
* @access public
* @return mixed
*/
#[\ReturnTypeWillChange]
public function key()
{
return key($this->currentConfig);
@@ -222,6 +224,7 @@ class Config implements \Iterator, \ArrayAccess
* @param mixed $offset
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->currentConfig[$offset] ?? null;
@@ -231,7 +234,7 @@ class Config implements \Iterator, \ArrayAccess
* @param mixed $offset
* @param mixed $value
*/
public function offsetSet($offset, $value)
public function offsetSet($offset, $value): void
{
$this->currentConfig[$offset] = $value;
}
@@ -239,7 +242,7 @@ class Config implements \Iterator, \ArrayAccess
/**
* @param mixed $offset
*/
public function offsetUnset($offset)
public function offsetUnset($offset): void
{
unset($this->currentConfig[$offset]);
}

View File

@@ -129,6 +129,14 @@ class Db
$this->adapter = new $adapterName();
}
/**
* @return Adapter
*/
public function getAdapter(): Adapter
{
return $this->adapter;
}
/**
* 获取适配器名称
*

View File

@@ -37,6 +37,13 @@ interface Adapter
*/
public function getVersion($handle): string;
/**
* 获取数据库类型
*
* @return string
*/
public function getDriver(): string;
/**
* 清空数据表
*

View File

@@ -29,4 +29,12 @@ trait MysqlTrait
{
return $this->buildQuery($sql);
}
/**
* @return string
*/
public function getDriver(): string
{
return 'mysql';
}
}

View File

@@ -64,7 +64,7 @@ class Mysqli implements Adapter
}
/** 数据库异常 */
throw new ConnectionException(@$this->dbLink->error, @$this->dbLink->errno);
throw new ConnectionException("Couldn't connect to database.", mysqli_connect_errno());
}
/**
@@ -75,7 +75,7 @@ class Mysqli implements Adapter
*/
public function getVersion($handle): string
{
return 'mysqli:mysql ' . $this->dbLink->server_version;
return $this->dbLink->server_version;
}
/**
@@ -86,7 +86,6 @@ class Mysqli implements Adapter
* @param integer $op 数据库读写状态
* @param string|null $action 数据库动作
* @param string|null $table 数据表
* @return \mysqli_result
* @throws SQLException
*/
public function query(
@@ -95,7 +94,7 @@ class Mysqli implements Adapter
int $op = Db::READ,
?string $action = null,
?string $table = null
): \mysqli_result {
) {
if ($resource = @$this->dbLink->query($query)) {
return $resource;
}
@@ -113,7 +112,7 @@ class Mysqli implements Adapter
*/
public function quoteColumn(string $string): string
{
return $this->dbLink->real_escape_string($string);
return '`' . $string . '`';
}
/**
@@ -157,13 +156,13 @@ class Mysqli implements Adapter
*/
public function quoteValue($string): string
{
return '\'' . str_replace(['\'', '\\'], ['\'\'', '\\\\'], $string) . '\'';
return "'" . $this->dbLink->real_escape_string($string) . "'";
}
/**
* 取出最后一次查询影响的行数
*
* @param \mysqli_result $resource 查询的资源数据
* @param mixed $resource 查询的资源数据
* @param \mysqli $handle 连接对象
* @return integer
*/
@@ -175,7 +174,7 @@ class Mysqli implements Adapter
/**
* 取出最后一次插入返回的主键值
*
* @param \mysqli_result $resource 查询的资源数据
* @param mixed $resource 查询的资源数据
* @param \mysqli $handle 连接对象
* @return integer
*/

View File

@@ -81,8 +81,7 @@ abstract class Pdo implements Adapter
*/
public function getVersion($handle): string
{
return 'pdo:' . $handle->getAttribute(\PDO::ATTR_DRIVER_NAME)
. ' ' . $handle->getAttribute(\PDO::ATTR_SERVER_VERSION);
return $handle->getAttribute(\PDO::ATTR_SERVER_VERSION);
}
/**

View File

@@ -63,7 +63,7 @@ class Pgsql implements Adapter
public function getVersion($handle): string
{
$version = pg_version($handle);
return 'pgsql:pgsql ' . $version['server'];
return $version['server'];
}
/**

View File

@@ -153,6 +153,14 @@ WHERE
return 0;
}
/**
* @return string
*/
public function getDriver(): string
{
return 'pgsql';
}
abstract public function query(
string $query,
$handle,

View File

@@ -20,10 +20,10 @@ trait QueryTrait
}
}
$sql['limit'] = (0 == strlen($sql['limit'])) ? null : ' LIMIT ' . $sql['limit'];
$sql['offset'] = (0 == strlen($sql['offset'])) ? null : ' OFFSET ' . $sql['offset'];
$sql['limit'] = isset($sql['limit']) ? ' LIMIT ' . $sql['limit'] : '';
$sql['offset'] = isset($sql['offset']) ? ' OFFSET ' . $sql['offset'] : '';
return 'SELECT ' . $sql['fields'] . ' FROM ' . $sql['table'] .
$sql['where'] . $sql['group'] . $sql['having'] . $sql['order'] . $sql['limit'] . $sql['offset'];
}
}
}

View File

@@ -57,7 +57,7 @@ class SQLite implements Adapter
*/
public function getVersion($handle): string
{
return 'sqlite:sqlite ' . \SQLite3::version()['versionString'];
return \SQLite3::version()['versionString'];
}
/**

View File

@@ -99,4 +99,12 @@ trait SQLiteTrait
return $query;
}
/**
* @return string
*/
public function getDriver(): string
{
return 'sqlite';
}
}

View File

@@ -21,7 +21,7 @@ use Typecho\Db;
class Query
{
/** 数据库关键字 */
private const KEYWORDS = '*PRIMARY|AND|OR|LIKE|BINARY|BY|DISTINCT|AS|IN|IS|NULL';
private const KEYWORDS = '*PRIMARY|AND|OR|LIKE|ILIKE|BINARY|BY|DISTINCT|AS|IN|IS|NULL';
/**
* 默认字段
@@ -512,7 +512,7 @@ class Query
return preg_replace_callback("/#param:([0-9]+)#/", function ($matches) use ($params, $adapter) {
if (array_key_exists($matches[1], $params)) {
return $adapter->quoteValue($params[$matches[1]]);
return is_null($params[$matches[1]]) ? 'NULL' : $adapter->quoteValue($params[$matches[1]]);
} else {
return $matches[0];
}

View File

@@ -2,12 +2,12 @@
namespace Typecho\Http;
use Typecho\Http\Client\Adapter;
use Typecho\Common;
use Typecho\Http\Client\Exception;
/**
* Http客户端
*
* @author qining
* @category typecho
* @package Http
*/
@@ -19,24 +19,359 @@ class Client
/** GET方法 */
public const METHOD_GET = 'GET';
/** 定义行结束符 */
public const EOL = "\r\n";
/** PUT方法 */
public const METHOD_PUT = 'PUT';
private const ADAPTERS = [Adapter\Curl::class, Adapter\Socket::class];
/** DELETE方法 */
public const METHOD_DELETE = 'DELETE';
/**
* 方法名
*
* @var string
*/
private $method = self::METHOD_GET;
/**
* 传递参数
*
* @var string
*/
private $query;
/**
* User Agent
*
* @var string
*/
private $agent;
/**
* 设置超时
*
* @var string
*/
private $timeout = 3;
/**
* @var bool
*/
private $multipart = true;
/**
* 需要在body中传递的值
*
* @var array|string
*/
private $data = [];
/**
* 头信息参数
*
* @access private
* @var array
*/
private $headers = [];
/**
* cookies
*
* @var array
*/
private $cookies = [];
/**
* @var array
*/
private $options = [];
/**
* 回执头部信息
*
* @var array
*/
private $responseHeader = [];
/**
* 回执代码
*
* @var integer
*/
private $responseStatus;
/**
* 回执身体
*
* @var string
*/
private $responseBody;
/**
* 设置指定的COOKIE值
*
* @param string $key 指定的参数
* @param mixed $value 设置的值
* @return $this
*/
public function setCookie(string $key, $value): Client
{
$this->cookies[$key] = $value;
return $this;
}
/**
* 设置传递参数
*
* @param mixed $query 传递参数
* @return $this
*/
public function setQuery($query): Client
{
$query = is_array($query) ? http_build_query($query) : $query;
$this->query = empty($this->query) ? $query : $this->query . '&' . $query;
return $this;
}
/**
* 设置需要POST的数据
*
* @param array|string $data 需要POST的数据
* @param string $method
* @return $this
*/
public function setData($data, string $method = self::METHOD_POST): Client
{
if (is_array($data) && is_array($this->data)) {
$this->data = array_merge($this->data, $data);
} else {
$this->data = $data;
}
$this->setMethod($method);
return $this;
}
/**
* 设置方法名
*
* @param string $method
* @return $this
*/
public function setMethod(string $method): Client
{
$this->method = $method;
return $this;
}
/**
* 设置需要POST的文件
*
* @param array $files 需要POST的文件
* @param string $method
* @return $this
*/
public function setFiles(array $files, string $method = self::METHOD_POST): Client
{
if (is_array($this->data)) {
foreach ($files as $name => $file) {
$this->data[$name] = new \CURLFile($file);
}
}
$this->setMethod($method);
return $this;
}
/**
* 设置超时时间
*
* @param integer $timeout 超时时间
* @return $this
*/
public function setTimeout(int $timeout): Client
{
$this->timeout = $timeout;
return $this;
}
/**
* setAgent
*
* @param string $agent
* @return $this
*/
public function setAgent(string $agent): Client
{
$this->agent = $agent;
return $this;
}
/**
* @param bool $multipart
* @return $this
*/
public function setMultipart(bool $multipart): Client
{
$this->multipart = $multipart;
return $this;
}
/**
* @param int $key
* @param mixed $value
* @return $this
*/
public function setOption(int $key, $value): Client
{
$this->options[$key] = $value;
return $this;
}
/**
* 设置头信息参数
*
* @param string $key 参数名称
* @param string $value 参数值
* @return $this
*/
public function setHeader(string $key, string $value): Client
{
$key = str_replace(' ', '-', ucwords(str_replace('-', ' ', $key)));
if ($key == 'User-Agent') {
$this->setAgent($value);
} else {
$this->headers[$key] = $value;
}
return $this;
}
/**
* 发送请求
*
* @param string $url 请求地址
* @throws Exception
*/
public function send(string $url)
{
$params = parse_url($url);
$query = empty($params['query']) ? '' : $params['query'];
if (!empty($this->query)) {
$query = empty($query) ? $this->query : '&' . $this->query;
}
if (!empty($query)) {
$params['query'] = $query;
}
$url = Common::buildUrl($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method);
if (isset($this->agent)) {
curl_setopt($ch, CURLOPT_USERAGENT, $this->agent);
}
/** 设置header信息 */
if (!empty($this->headers)) {
$headers = [];
foreach ($this->headers as $key => $val) {
$headers[] = $key . ': ' . $val;
}
if (!empty($this->cookies)) {
$headers[] = 'Cookie: ' . str_replace('&', '; ', http_build_query($this->cookies));
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
if (!empty($this->data)) {
$data = $this->data;
if (!$this->multipart) {
curl_setopt($ch, CURLOPT_POST, true);
$data = is_array($data) ? http_build_query($data) : $data;
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) {
$parts = explode(':', $header, 2);
if (count($parts) == 2) {
[$key, $value] = $parts;
$this->responseHeader[strtolower(trim($key))] = trim($value);
}
return strlen($header);
});
foreach ($this->options as $key => $val) {
curl_setopt($ch, $key, $val);
}
$response = curl_exec($ch);
if (false === $response) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception($error, 500);
}
$this->responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->responseBody = $response;
curl_close($ch);
}
/**
* 获取回执的头部信息
*
* @param string $key 头信息名称
* @return string
*/
public function getResponseHeader(string $key): ?string
{
$key = strtolower($key);
return $this->responseHeader[$key] ?? null;
}
/**
* 获取回执代码
*
* @return integer
*/
public function getResponseStatus(): int
{
return $this->responseStatus;
}
/**
* 获取回执身体
*
* @return string
*/
public function getResponseBody(): string
{
return $this->responseBody;
}
/**
* 获取可用的连接
*
* @return ?Adapter
* @return ?Client
*/
public static function get(): ?Adapter
public static function get(): ?Client
{
foreach (self::ADAPTERS as $adapter) {
if (call_user_func([$adapter, 'isAvailable'])) {
return new $adapter();
}
}
return null;
return extension_loaded('curl') ? new static() : null;
}
}

View File

@@ -1,421 +0,0 @@
<?php
namespace Typecho\Http\Client;
use Typecho\Common;
use Typecho\Http\Client;
/**
* 客户端适配器
*
* @author qining
* @category typecho
* @package Http
*/
abstract class Adapter
{
/**
* 方法名
*
* @access protected
* @var string
*/
protected $method = Client::METHOD_GET;
/**
* 传递参数
*
* @access protected
* @var string
*/
protected $query;
/**
* 设置超时
*
* @access protected
* @var string
*/
protected $timeout = 3;
/**
* 需要在body中传递的值
*
* @access protected
* @var array|string
*/
protected $data = [];
/**
* 文件列表
*
* @access protected
* @var array
*/
protected $files = [];
/**
* 头信息参数
*
* @access protected
* @var array
*/
protected $headers = [];
/**
* cookies
*
* @access protected
* @var array
*/
protected $cookies = [];
/**
* 协议名称及版本
*
* @access protected
* @var string
*/
protected $rfc = 'HTTP/1.1';
/**
* 请求地址
*
* @access protected
* @var string
*/
protected $url;
/**
* 主机名
*
* @access protected
* @var string
*/
protected $host;
/**
* 前缀
*
* @access protected
* @var string
*/
protected $scheme = 'http';
/**
* 路径
*
* @access protected
* @var string
*/
protected $path = '/';
/**
* 设置ip
*
* @access protected
* @var string
*/
protected $ip;
/**
* 端口
*
* @access protected
* @var integer
*/
protected $port = 80;
/**
* 回执头部信息
*
* @access protected
* @var array
*/
protected $responseHeader = [];
/**
* 回执代码
*
* @access protected
* @var integer
*/
protected $responseStatus;
/**
* 回执身体
*
* @access protected
* @var string
*/
protected $responseBody;
/**
* 判断适配器是否可用
*
* @access public
* @return boolean
*/
abstract public static function isAvailable(): bool;
/**
* 设置指定的COOKIE值
*
* @access public
* @param string $key 指定的参数
* @param mixed $value 设置的值
* @return $this
*/
public function setCookie(string $key, $value): Adapter
{
$this->cookies[$key] = $value;
return $this;
}
/**
* 设置传递参数
*
* @access public
* @param mixed $query 传递参数
* @return $this
*/
public function setQuery($query): Adapter
{
$query = is_array($query) ? http_build_query($query) : $query;
$this->query = empty($this->query) ? $query : $this->query . '&' . $query;
return $this;
}
/**
* 设置需要POST的数据
*
* @access public
* @param array|string $data 需要POST的数据
* @return $this
*/
public function setData($data): Adapter
{
$this->data = $data;
$this->setMethod(Client::METHOD_POST);
return $this;
}
/**
* 设置方法名
*
* @access public
* @param string $method
* @return $this
*/
public function setMethod(string $method): Adapter
{
$this->method = $method;
return $this;
}
/**
* 设置需要POST的文件
*
* @access public
* @param array $files 需要POST的文件
* @return $this
*/
public function setFiles(array $files): Adapter
{
$this->files = empty($this->files) ? $files : array_merge($this->files, $files);
$this->setMethod(Client::METHOD_POST);
return $this;
}
/**
* 设置超时时间
*
* @access public
* @param integer $timeout 超时时间
* @return $this
*/
public function setTimeout(int $timeout): Adapter
{
$this->timeout = $timeout;
return $this;
}
/**
* 设置http协议
*
* @access public
* @param string $rfc http协议
* @return $this
*/
public function setRfc(string $rfc): Adapter
{
$this->rfc = $rfc;
return $this;
}
/**
* 设置ip地址
*
* @access public
* @param string $ip ip地址
* @return $this
*/
public function setIp(string $ip): Adapter
{
$this->ip = $ip;
return $this;
}
/**
* 发送请求
*
* @access public
* @param string $url 请求地址
* @return string|null
* @throws Exception
*/
public function send(string $url): ?string
{
$params = parse_url($url);
if (!empty($params['host'])) {
$this->host = $params['host'];
} else {
throw new Exception('Unknown Host', 500);
}
if (!in_array($params['scheme'], ['http', 'https'])) {
throw new Exception('Unknown Scheme', 500);
}
if (!empty($params['path'])) {
$this->path = $params['path'];
}
$query = empty($params['query']) ? '' : $params['query'];
if (!empty($this->query)) {
$query = empty($query) ? $this->query : '&' . $this->query;
}
if (!empty($query)) {
$this->path .= '?' . $query;
$params['query'] = $query;
}
$this->scheme = $params['scheme'];
$this->port = ('https' == $params['scheme']) ? 443 : 80;
$url = Common::buildUrl($params);
if (!empty($params['port'])) {
$this->port = $params['port'];
}
/** 整理cookie */
if (!empty($this->cookies)) {
$this->setHeader('Cookie', str_replace('&', '; ', http_build_query($this->cookies)));
}
$response = $this->httpSend($url);
if (!$response) {
return null;
}
str_replace("\r", '', $response);
$rows = explode("\n", $response);
$foundStatus = false;
$foundInfo = false;
$lines = [];
foreach ($rows as $key => $line) {
if (!$foundStatus) {
if (0 === strpos($line, "HTTP/")) {
if ('' == trim($rows[$key + 1])) {
continue;
} else {
$status = explode(' ', str_replace(' ', ' ', $line));
$this->responseStatus = intval($status[1]);
$foundStatus = true;
}
}
} else {
if (!$foundInfo) {
if ('' != trim($line)) {
$status = explode(':', $line);
$name = strtolower(array_shift($status));
$data = implode(':', $status);
$this->responseHeader[trim($name)] = trim($data);
} else {
$foundInfo = true;
}
} else {
$lines[] = $line;
}
}
}
$this->responseBody = implode("\n", $lines);
return $this->responseBody;
}
/**
* 设置头信息参数
*
* @access public
* @param string $key 参数名称
* @param string $value 参数值
* @return $this
*/
public function setHeader(string $key, string $value): Adapter
{
$key = str_replace(' ', '-', ucwords(str_replace('-', ' ', $key)));
$this->headers[$key] = $value;
return $this;
}
/**
* 需要实现的请求方法
*
* @access public
* @param string $url 请求地址
* @return string
*/
abstract protected function httpSend(string $url): string;
/**
* 获取回执的头部信息
*
* @access public
* @param string $key 头信息名称
* @return string
*/
public function getResponseHeader(string $key): ?string
{
$key = strtolower($key);
return $this->responseHeader[$key] ?? null;
}
/**
* 获取回执代码
*
* @access public
* @return integer
*/
public function getResponseStatus(): int
{
return $this->responseStatus;
}
/**
* 获取回执身体
*
* @access public
* @return string
*/
public function getResponseBody(): string
{
return $this->responseBody;
}
}

View File

@@ -1,124 +0,0 @@
<?php
namespace Typecho\Http\Client\Adapter;
use Typecho\Http\Client;
use Typecho\Http\Client\Adapter;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* CURL适配器
*
* @author qining
* @category typecho
* @package Http
*/
class Curl extends Adapter
{
/**
* 判断适配器是否可用
*
* @access public
* @return boolean
*/
public static function isAvailable(): bool
{
return function_exists('curl_version');
}
/**
* 发送请求
*
* @access public
* @param string $url 请求地址
* @return string
* @throws Client\Exception
*/
protected function httpSend(string $url): string
{
$ch = curl_init();
if ($this->ip) {
$url = $this->scheme . '://' . $this->ip . $this->path;
$this->headers['Rfc'] = $this->method . ' ' . $this->path . ' ' . $this->rfc;
$this->headers['Host'] = $this->host;
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PORT, $this->port);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
/** 设置HTTP版本 */
switch ($this->rfc) {
case 'HTTP/1.0':
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
break;
case 'HTTP/1.1':
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
break;
default:
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
break;
}
/** 设置header信息 */
if (!empty($this->headers)) {
if (isset($this->headers['User-Agent'])) {
curl_setopt($ch, CURLOPT_USERAGENT, $this->headers['User-Agent']);
unset($this->headers['User-Agent']);
}
$headers = [];
if (isset($this->headers['Rfc'])) {
$headers[] = $this->headers['Rfc'];
unset($this->headers['Rfc']);
}
foreach ($this->headers as $key => $val) {
$headers[] = $key . ': ' . $val;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
/** POST模式 */
if (Client::METHOD_POST == $this->method) {
if (!isset($this->headers['content-type'])) {
curl_setopt($ch, CURLOPT_POST, true);
}
if (!empty($this->data)) {
curl_setopt(
$ch,
CURLOPT_POSTFIELDS,
is_array($this->data) ? http_build_query($this->data) : $this->data
);
}
if (!empty($this->files)) {
foreach ($this->files as &$file) {
$file = '@' . $file;
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->files);
}
}
$response = curl_exec($ch);
if (false === $response) {
throw new Client\Exception(curl_error($ch), 500);
}
curl_close($ch);
return $response;
}
}

View File

@@ -1,161 +0,0 @@
<?php
namespace Typecho\Http\Client\Adapter;
use Typecho\Http\Client;
use Typecho\Http\Client\Adapter;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* Socket适配器
*
* @author qining
* @category typecho
* @package Http
*/
class Socket extends Adapter
{
/**
* 判断适配器是否可用
*
* @access public
* @return boolean
*/
public static function isAvailable(): bool
{
return function_exists("fsockopen");
}
/**
* 获取回执身体
*
* @access public
* @return string
*/
public function getResponseBody(): string
{
/** 支持chunked编码 */
if ('chunked' == $this->getResponseHeader('Transfer-Encoding')) {
$parts = explode("\r\n", $this->responseBody, 2);
$counter = hexdec($parts[0]);
$this->responseBody = substr($parts[1], 0, $counter);
}
return $this->responseBody;
}
/**
* 发送请求
*
* @access public
* @param string $url 请求地址
* @return string
* @throws Client\Exception
*/
protected function httpSend(string $url): string
{
$eol = Client::EOL;
$request = $this->method . ' ' . $this->path . ' ' . $this->rfc . $eol;
$request .= 'Host: ' . $this->host . $eol;
$request .= 'Accept: */*' . $eol;
$request .= 'Cache-Control: no-cache' . $eol;
$request .= 'Connection: Close' . $eol;
/** 设置header信息 */
if (!empty($this->headers)) {
foreach ($this->headers as $key => $val) {
$request .= $key . ': ' . $val . $eol;
}
}
/** 发送POST信息 */
if (Client::METHOD_POST == $this->method) {
if (empty($this->files)) {
$content = is_array($this->data) ? http_build_query($this->data) : $this->data;
$request .= 'Content-Length: ' . strlen($content) . $eol;
if (!isset($this->headers['content-type'])) {
$request .= 'Content-Type: application/x-www-form-urlencoded' . $eol;
}
} else {
$boundary = '---------------------------' . substr(md5(uniqid()), 0, 16);
$content = $eol . $boundary;
if (!empty($this->data)) {
foreach ($this->data as $key => $val) {
$content .= $eol . 'Content-Disposition: form-data; name="' . $key . '"' . $eol . $eol;
$content .= $val . $eol;
$content .= $boundary;
}
}
foreach ($this->files as $key => $file) {
$content .= $eol . 'Content-Disposition: form-data; name="' . $key
. '"; filename="' . $file . '"' . $eol;
$content .= 'Content-Type: ' . mime_content_type($file) . $eol . $eol;
$content .= file_get_contents($file) . $eol;
$content .= $boundary;
}
$content .= '--' . $eol;
$request .= 'Content-Length: ' . strlen($content) . $eol;
$request .= 'Content-Type: multipart/form-data; boundary=' . $boundary;
}
$request .= $eol;
$request .= $content;
} else {
$request .= $eol;
}
/** 打开连接 */
$socket = @fsockopen($this->ip ?: $this->host, $this->port, $errno, $errstr, $this->timeout);
if (false === $socket) {
throw new Client\Exception($errno . ':' . $errstr, 500);
}
/** 发送数据 */
fwrite($socket, $request);
stream_set_timeout($socket, $this->timeout);
$response = '';
//facebook code
while (!feof($socket)) {
$buf = fgets($socket, 4096);
if (false === $buf || '' === $buf) {
$info = stream_get_meta_data($socket);
//超时判断
if ($info['timed_out']) {
throw new Client\Exception(
__CLASS__ . ': timeout reading from ' . $this->host . ':' . $this->port,
500
);
} else {
throw new Client\Exception(
__CLASS__ . ': could not read from ' . $this->host . ':' . $this->port,
500
);
}
} elseif (strlen($buf) < 4096) {
$info = stream_get_meta_data($socket);
if ($info['timed_out']) {
throw new Client\Exception(
__CLASS__ . ': timeout reading from ' . $this->host . ':' . $this->port,
500
);
}
}
$response .= $buf;
}
fclose($socket);
return $response;
}
}

View File

@@ -61,7 +61,6 @@ class I18n
* @param string $single 单数形式的翻译
* @param string $plural 复数形式的翻译
* @param integer $number 数字
*
* @return string
*/
public static function ngettext(string $single, string $plural, int $number): string

View File

@@ -167,7 +167,7 @@ class GetText
} else {
$result = $this->cache_translations[$key];
$list = explode(chr(0), $result);
return $list[$select];
return $list[$select] ?? '';
}
} else {
$num = $this->findString($key);
@@ -176,7 +176,7 @@ class GetText
} else {
$result = $this->getTranslationString($num);
$list = explode(chr(0), $result);
return $list[$select];
return $list[$select] ?? '';
}
}
}

View File

@@ -165,7 +165,11 @@ class Request
$this->params = null;
}
return $value ?? $default;
if (isset($value)) {
return is_array($default) == is_array($value) ? $value : $default;
} else {
return $default;
}
}
/**
@@ -199,9 +203,13 @@ class Request
*/
public function getArray($key): array
{
$result = $this->get($key, []);
$result = $this->get($key, [], $exists);
return is_array($result) ? $result : [$result];
if (!empty($result) || !$exists) {
return $result;
}
return [$this->get($key)];
}
/**
@@ -297,7 +305,7 @@ class Request
return $this->pathInfo;
}
//参考Zend Framework对pahtinfo的处理, 更好的兼容性
//参考Zend Framework对pathinfo的处理, 更好的兼容性
$pathInfo = null;
//处理requestUri
@@ -461,7 +469,7 @@ class Request
*/
public function isAjax(): bool
{
return 'XMLHttpRequest' == $this->getServer('HTTP_X_REQUESTED_WITH');
return 'XMLHttpRequest' == $this->getHeader('X-Requested-With');
}
/**

View File

@@ -203,12 +203,13 @@ class Response
[$key, $value, $timeout, $path, $domain] = $cookie;
if ($timeout > 0) {
$timeout += time();
$now = time();
$timeout += $timeout > $now - 86400 ? 0 : $now;
} elseif ($timeout < 0) {
$timeout = 1;
}
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain);
setrawcookie($key, rawurlencode($value), $timeout, $path, $domain ?? '');
}
}

View File

@@ -221,7 +221,7 @@ class Validate
* @access public
*
* @param string $key 数值键值
* @param string|array $rule 规则名称
* @param string|callable $rule 规则名称
* @param string $message 错误字符串
*
* @return $this
@@ -271,12 +271,12 @@ class Validate
foreach ($rules as $key => $rule) {
$this->key = $key;
$data[$key] = (is_array($data[$key]) ? 0 == count($data[$key])
: 0 == strlen($data[$key])) ? null : $data[$key];
: 0 == strlen($data[$key] ?? '')) ? null : $data[$key];
foreach ($rule as $params) {
$method = $params[0];
if ('required' != $method && 'confirm' != $method && 0 == strlen($data[$key])) {
if ('required' != $method && 'confirm' != $method && 0 == strlen($data[$key] ?? '')) {
continue;
}
@@ -284,7 +284,7 @@ class Validate
$params[1] = $data[$key];
$params = array_slice($params, 1);
if (!call_user_func_array(is_array($method) ? $method : [$this, $method], $params)) {
if (!call_user_func_array(is_callable($method) ? $method : [$this, $method], $params)) {
$result[$key] = $message;
break;
}
@@ -319,11 +319,9 @@ class Validate
*
* @access public
*
* @param string|null $str 待处理的字符串
*
* @return boolean
*/
public function required(?string $str): bool
public function required(): bool
{
return !empty($this->data[$this->key]);
}

View File

@@ -190,19 +190,24 @@ abstract class Widget
/**
* alloc widget instance with alias
*
* @param string $alias
* @param string|null $alias
* @param mixed $params
* @param mixed $request
* @param bool|callable $disableSandboxOrCallback
* @return $this
*/
public static function allocWithAlias(
string $alias,
?string $alias,
$params = null,
$request = null,
$disableSandboxOrCallback = true
): Widget {
return self::widget(static::class . '@' . $alias, $params, $request, $disableSandboxOrCallback);
return self::widget(
static::class . (isset($alias) ? '@' . $alias : ''),
$params,
$request,
$disableSandboxOrCallback
);
}
/**

View File

@@ -44,6 +44,10 @@ class Text extends Element
*/
protected function inputValue($value)
{
$this->input->setAttribute('value', htmlspecialchars($value));
if (isset($value)) {
$this->input->setAttribute('value', htmlspecialchars($value));
} else {
$this->input->removeAttribute('value');
}
}
}

View File

@@ -186,8 +186,8 @@ class Response
}
$this->redirect($referer);
} elseif (!empty($default)) {
$this->redirect($default);
} else {
$this->redirect($default ?: '/');
}
}

View File

@@ -1453,10 +1453,10 @@ class HyperDown
foreach ($lines as $key => $line) {
if (preg_match("/^(\s{" . $space . "})((?:[0-9]+\.?)|\-|\+|\*)(\s+)(.*)$/i", $line, $matches)) {
if ($type == 'ol' && $key == 0) {
$start = intval($matches[2]);
$olStart = intval($matches[2]);
if ($start != 1) {
$suffix = ' start="' . $start . '"';
if ($olStart != 1) {
$suffix = ' start="' . $olStart . '"';
}
}

View File

@@ -54,20 +54,17 @@ class Ajax extends BaseOptions implements ActionInterface
$json = json_decode($response, true);
if (!empty($json)) {
[$soft, $version] = explode(' ', $this->options->generator);
$current = explode('/', $version);
$version = $this->options->version;
if (
isset($json['release']) && isset($json['version'])
isset($json['release'])
&& preg_match("/^[0-9\.]+$/", $json['release'])
&& preg_match("/^[0-9\.]+$/", $json['version'])
&& version_compare($json['release'], $current[0], '>=')
&& version_compare($json['version'], $current[1], '>')
&& version_compare($json['release'], $version, '>=')
) {
$result = [
'available' => 1,
'latest' => $json['release'] . '-' . $json['version'],
'current' => $current[0] . '-' . $current[1],
'latest' => $json['release'],
'current' => $version,
'link' => 'http://typecho.org/download'
];
}

View File

@@ -37,7 +37,6 @@ class Archive extends Contents
/**
* 调用的风格文件
*
* @access private
* @var string
*/
private $themeFile;
@@ -45,7 +44,6 @@ class Archive extends Contents
/**
* 风格目录
*
* @access private
* @var string
*/
private $themeDir;
@@ -53,7 +51,6 @@ class Archive extends Contents
/**
* 分页计算对象
*
* @access private
* @var Query
*/
private $countSql;
@@ -61,7 +58,6 @@ class Archive extends Contents
/**
* 所有文章个数
*
* @access private
* @var integer
*/
private $total = false;
@@ -69,7 +65,6 @@ class Archive extends Contents
/**
* 标记是否为从外部调用
*
* @access private
* @var boolean
*/
private $invokeFromOutside = false;
@@ -77,7 +72,6 @@ class Archive extends Contents
/**
* 是否由聚合调用
*
* @access private
* @var boolean
*/
private $invokeByFeed = false;
@@ -85,7 +79,6 @@ class Archive extends Contents
/**
* 当前页
*
* @access private
* @var integer
*/
private $currentPage;
@@ -93,7 +86,6 @@ class Archive extends Contents
/**
* 生成分页的内容
*
* @access private
* @var array
*/
private $pageRow = [];
@@ -101,7 +93,6 @@ class Archive extends Contents
/**
* 聚合器对象
*
* @access private
* @var Feed
*/
private $feed;
@@ -109,7 +100,6 @@ class Archive extends Contents
/**
* RSS 2.0聚合地址
*
* @access private
* @var string
*/
private $feedUrl;
@@ -117,7 +107,6 @@ class Archive extends Contents
/**
* RSS 1.0聚合地址
*
* @access private
* @var string
*/
private $feedRssUrl;
@@ -125,7 +114,6 @@ class Archive extends Contents
/**
* ATOM 聚合地址
*
* @access private
* @var string
*/
private $feedAtomUrl;
@@ -133,7 +121,6 @@ class Archive extends Contents
/**
* 本页关键字
*
* @access private
* @var string
*/
private $keywords;
@@ -141,7 +128,6 @@ class Archive extends Contents
/**
* 本页描述
*
* @access private
* @var string
*/
private $description;
@@ -149,7 +135,6 @@ class Archive extends Contents
/**
* 聚合类型
*
* @access private
* @var string
*/
private $feedType;
@@ -157,7 +142,6 @@ class Archive extends Contents
/**
* 聚合类型
*
* @access private
* @var string
*/
private $feedContentType;
@@ -165,7 +149,6 @@ class Archive extends Contents
/**
* 当前feed地址
*
* @access private
* @var string
*/
private $currentFeedUrl;
@@ -173,15 +156,20 @@ class Archive extends Contents
/**
* 归档标题
*
* @access private
* @var string
*/
private $archiveTitle = null;
/**
* 归档地址
*
* @var string|null
*/
private $archiveUrl = null;
/**
* 归档类型
*
* @access private
* @var string
*/
private $archiveType = 'index';
@@ -189,7 +177,6 @@ class Archive extends Contents
/**
* 是否为单一归档
*
* @access private
* @var string
*/
private $archiveSingle = false;
@@ -392,6 +379,22 @@ class Archive extends Contents
$this->archiveType = $archiveType;
}
/**
* @return string|null
*/
public function getArchiveUrl(): ?string
{
return $this->archiveUrl;
}
/**
* @param string|null $archiveUrl
*/
public function setArchiveUrl(?string $archiveUrl): void
{
$this->archiveUrl = $archiveUrl;
}
/**
* @return string|null
*/
@@ -528,6 +531,16 @@ class Archive extends Contents
return $this->currentPage;
}
/**
* _currentPage
*
* @return int
*/
public function ____currentPage(): int
{
return $this->getCurrentPage();
}
/**
* 获取页数
*
@@ -663,7 +676,7 @@ class Archive extends Contents
}
/** 初始化分页变量 */
$this->currentPage = $this->request->page ?? 1;
$this->currentPage = $this->request->filter('int')->page ?? 1;
$hasPushed = false;
/** select初始化 */
@@ -716,6 +729,7 @@ class Archive extends Contents
$this->feedAtomUrl = $this->options->feedAtomUrl;
$this->keywords = $this->options->keywords;
$this->description = $this->options->description;
$this->archiveUrl = $this->options->siteUrl;
if (isset($handles[$this->parameter->type])) {
$handle = $handles[$this->parameter->type];
@@ -747,6 +761,11 @@ class Archive extends Contents
$select->order('table.contents.created', Db::SORT_DESC)
->page($this->currentPage, $this->parameter->pageSize);
$this->query($select);
/** 处理超出分页的情况 */
if ($this->currentPage > 1 && !$this->have()) {
throw new WidgetException(_t('请求的地址不存在'), 404);
}
}
/**
@@ -1270,7 +1289,7 @@ class Archive extends Contents
if ($return) {
return $value;
} else {
echo htmlspecialchars($value);
echo htmlspecialchars($value ?? '');
}
}
@@ -1406,13 +1425,19 @@ class Archive extends Contents
*/
public function feed()
{
$this->feed->setSubTitle($this->description);
$this->feed->setFeedUrl($this->currentFeedUrl);
if ($this->feedType == Feed::RSS1) {
$feedUrl = $this->feedRssUrl;
} elseif ($this->feedType == Feed::ATOM1) {
$feedUrl = $this->feedAtomUrl;
} else {
$feedUrl = $this->feedUrl;
}
$this->feed->setBaseUrl(('/' == $this->request->feed || 0 == strlen($this->request->feed)
|| '/comments' == $this->request->feed || '/comments/' == $this->request->feed) ?
$this->options->siteUrl : Common::url($this->request->feed, $this->options->index));
$this->feed->setFeedUrl($this->request->makeUriByRequest());
$this->checkPermalink($feedUrl);
$this->feed->setSubTitle($this->description);
$this->feed->setFeedUrl($feedUrl);
$this->feed->setBaseUrl($this->archiveUrl);
if ($this->is('single') || 'comments' == $this->parameter->type) {
$this->feed->setTitle(_t(
@@ -1473,7 +1498,7 @@ class Archive extends Contents
'date' => $this->created,
'link' => $this->permalink,
'author' => $this->author,
'excerpt' => $this->description,
'excerpt' => $this->___description(),
'comments' => $this->commentsNum,
'commentsFeedUrl' => $feedUrl,
'suffix' => $suffix
@@ -1572,28 +1597,32 @@ class Archive extends Contents
/**
* 检查链接是否正确
*
* @param string|null $permalink
*/
private function checkPermalink()
private function checkPermalink(?string $permalink = null)
{
$type = $this->parameter->type;
if (!isset($permalink)) {
$type = $this->parameter->type;
if (
in_array($type, ['index', 'comment_page', 404])
|| $this->makeSinglePageAsFrontPage // 自定义首页不处理
|| !$this->parameter->checkPermalink
) { // 强制关闭
return;
}
if (
in_array($type, ['index', 'comment_page', 404])
|| $this->makeSinglePageAsFrontPage // 自定义首页不处理
|| !$this->parameter->checkPermalink
) { // 强制关闭
return;
}
if ($this->archiveSingle) {
$permalink = $this->permalink;
} else {
$value = array_merge($this->pageRow, [
'page' => $this->currentPage
]);
if ($this->archiveSingle) {
$permalink = $this->permalink;
} else {
$value = array_merge($this->pageRow, [
'page' => $this->currentPage
]);
$path = Router::url($type, $value);
$permalink = Common::url($path, $this->options->index);
$path = Router::url($type, $value);
$permalink = Common::url($path, $this->options->index);
}
}
$requestUrl = $this->request->getRequestUrl();
@@ -1749,8 +1778,7 @@ class Archive extends Contents
$this->security->protect();
Cookie::set(
'protectPassword_' . $this->request->filter('int')->protectCID,
$this->request->protectPassword,
0
$this->request->protectPassword
);
$isPasswordPosted = true;
@@ -1816,6 +1844,9 @@ class Archive extends Contents
/** 设置归档缩略名 */
$this->archiveSlug = ('post' == $this->type || 'attachment' == $this->type) ? $this->cid : $this->slug;
/** 设置归档地址 */
$this->archiveUrl = $this->permalink;
/** 设置403头 */
if ($this->hidden) {
$this->response->setStatus(403);
@@ -1907,6 +1938,9 @@ class Archive extends Contents
/** 设置归档缩略名 */
$this->archiveSlug = $category['slug'];
/** 设置归档地址 */
$this->archiveUrl = $category['permalink'];
/** 插件接口 */
self::pluginHandle()->categoryHandle($this, $select);
}
@@ -1976,6 +2010,9 @@ class Archive extends Contents
/** 设置归档缩略名 */
$this->archiveSlug = $tag['slug'];
/** 设置归档地址 */
$this->archiveUrl = $tag['permalink'];
/** 插件接口 */
self::pluginHandle()->tagHandle($this, $select);
}
@@ -2032,6 +2069,9 @@ class Archive extends Contents
/** 设置归档缩略名 */
$this->archiveSlug = $author['uid'];
/** 设置归档地址 */
$this->archiveUrl = $author['permalink'];
/** 插件接口 */
self::pluginHandle()->authorHandle($this, $select);
}
@@ -2115,6 +2155,9 @@ class Archive extends Contents
/** ATOM 1.0 */
$this->feedAtomUrl = Router::url($currentRoute, $value, $this->options->feedAtomUrl);
/** 设置归档地址 */
$this->archiveUrl = Router::url($currentRoute, $value, $this->options->index);
/** 插件接口 */
self::pluginHandle()->dateHandle($this, $select);
}
@@ -2146,7 +2189,9 @@ class Archive extends Contents
$select->where("table.contents.password IS NULL OR table.contents.password = ''");
}
$select->where('table.contents.title LIKE ? OR table.contents.text LIKE ?', $searchQuery, $searchQuery)
$op = $this->db->getAdapter()->getDriver() == 'pgsql' ? 'ILIKE' : 'LIKE';
$select->where("table.contents.title {$op} ? OR table.contents.text {$op} ?", $searchQuery, $searchQuery)
->where('table.contents.type = ?', 'post');
}
@@ -2175,6 +2220,9 @@ class Archive extends Contents
/** 设置归档缩略名 */
$this->archiveSlug = $keywords;
/** 设置归档地址 */
$this->archiveUrl = Router::url('search', ['keywords' => $keywords], $this->options->index);
/** 插件接口 */
self::pluginHandle()->searchHandle($this, $select);
}

View File

@@ -4,7 +4,6 @@ namespace Widget;
use Typecho\Config;
use Typecho\Db;
use Typecho\Plugin;
use Typecho\Widget;
if (!defined('__TYPECHO_ROOT_DIR__')) {

View File

@@ -234,6 +234,14 @@ class Comments extends Base implements QueryInterface
*/
public function filter(array $value): array
{
/** 处理默认空值 */
$value['author'] = $value['author'] ?? '';
$value['mail'] = $value['mail'] ?? '';
$value['url'] = $value['url'] ?? '';
$value['ip'] = $value['ip'] ?? '';
$value['agent'] = $value['agent'] ?? '';
$value['text'] = $value['text'] ?? '';
$value['date'] = new Date($value['created']);
return Comments::pluginHandle()->filter($value, $this);
}

View File

@@ -487,6 +487,11 @@ class Contents extends Base implements QueryInterface
*/
public function filter(array $value): array
{
/** 处理默认空值 */
$value['title'] = $value['title'] ?? '';
$value['text'] = $value['text'] ?? '';
$value['slug'] = $value['slug'] ?? '';
/** 取出所有分类 */
$value['categories'] = $this->db->fetchAll($this->db
->select()->from('table.metas')
@@ -494,7 +499,7 @@ class Contents extends Base implements QueryInterface
->where('table.relationships.cid = ?', $value['cid'])
->where('table.metas.type = ?', 'category'), [Rows::alloc(), 'filter']);
$value['category'] = null;
$value['category'] = '';
$value['directory'] = [];
/** 取出第一个分类作为slug条件 */
@@ -585,7 +590,7 @@ class Contents extends Base implements QueryInterface
/** 处理密码保护流程 */
if (
strlen($value['password']) > 0 &&
strlen($value['password'] ?? '') > 0 &&
$value['password'] !== Cookie::get('protectPassword_' . $value['cid']) &&
$value['authorId'] != $this->user->uid &&
!$this->user->pass('editor', true)
@@ -792,7 +797,9 @@ class Contents extends Base implements QueryInterface
*/
public function author(string $item = 'screenName')
{
echo $this->author->{$item};
if ($this->have()) {
echo $this->author->{$item};
}
}
/**
@@ -813,9 +820,9 @@ class Contents extends Base implements QueryInterface
/**
* 文章作者
*
* @return Widget
* @return Users
*/
protected function ___author(): Widget
protected function ___author(): Users
{
return Author::allocWithAlias($this->cid, ['uid' => $this->authorId]);
}

View File

@@ -91,16 +91,16 @@ class Metas extends Base implements QueryInterface
/**
* 获取最大排序
*
* @param mixed $type
* @param string $type
* @param int $parent
* @return integer
* @throws Exception
*/
public function getMaxOrder($type, int $parent = 0): int
public function getMaxOrder(string $type, int $parent = 0): int
{
return $this->db->fetchObject($this->db->select(['MAX(order)' => 'maxOrder'])
->from('table.metas')
->where('type = ? AND parent = ?', 'category', $parent))->maxOrder;
->where('type = ? AND parent = ?', $type, $parent))->maxOrder ?? 0;
}
/**

View File

@@ -275,7 +275,7 @@ class Edit extends Comments implements ActionInterface
}
/** 评论插件接口 */
self::pluginHandle()->edit($comment, $this);
$comment = self::pluginHandle()->edit($comment, $this);
/** 更新评论 */
$this->update($comment, $this->db->sql()->where('coid = ?', $coid));

View File

@@ -37,10 +37,7 @@ class Edit extends PostEdit implements ActionInterface
$this->user->pass('contributor');
/** 获取文章内容 */
if (
(isset($this->request->cid) && 'delete' != $this->request->do
&& 'insert' != $this->request->do) || 'update' == $this->request->do
) {
if (!empty($this->request->cid)) {
$this->db->fetchRow($this->select()
->where('table.contents.type = ?', 'attachment')
->where('table.contents.cid = ?', $this->request->filter('int')->cid)
@@ -344,7 +341,7 @@ class Edit extends PostEdit implements ActionInterface
{
$this->security->protect();
$this->on($this->request->is('do=delete'))->deleteAttachment();
$this->on($this->request->is('do=update'))->updateAttachment();
$this->on($this->have() && $this->request->is('do=update'))->updateAttachment();
$this->on($this->request->is('do=clear'))->clearAttachment();
$this->response->redirect($this->options->adminUrl);
}

View File

@@ -47,7 +47,7 @@ class Edit extends PostEdit implements ActionInterface
$this->user->pass('editor');
/** 获取文章内容 */
if (!empty($this->request->cid) && 'delete' != $this->request->do && 'sort' != $this->request->do) {
if (!empty($this->request->cid)) {
$this->db->fetchRow($this->select()
->where('table.contents.type = ? OR table.contents.type = ?', 'page', 'page_draft')
->where('table.contents.cid = ?', $this->request->filter('int')->cid)

View File

@@ -45,7 +45,7 @@ class Edit extends Contents implements ActionInterface
$this->user->pass('contributor');
/** 获取文章内容 */
if (!empty($this->request->cid) && 'delete' != $this->request->do) {
if (!empty($this->request->cid)) {
$this->db->fetchRow($this->select()
->where('table.contents.type = ? OR table.contents.type = ?', 'post', 'post_draft')
->where('table.contents.cid = ?', $this->request->filter('int')->cid)

View File

@@ -216,7 +216,7 @@ class Feedback extends Comments implements ActionInterface
}
}
$expire = $this->options->time + $this->options->timezone + 30 * 24 * 3600;
$expire = 30 * 24 * 3600;
Cookie::set('__typecho_remember_author', $comment['author'], $expire);
Cookie::set('__typecho_remember_mail', $comment['mail'], $expire);
Cookie::set('__typecho_remember_url', $comment['url'], $expire);

View File

@@ -41,6 +41,14 @@ class Login extends Users implements ActionInterface
$validator = new Validate();
$validator->addRule('name', 'required', _t('请输入用户名'));
$validator->addRule('password', 'required', _t('请输入密码'));
$expire = 30 * 24 * 3600;
/** 记住密码状态 */
if ($this->request->remember) {
Cookie::set('__typecho_remember_remember', 1, $expire);
} elseif (Cookie::get('__typecho_remember_remember')) {
Cookie::delete('__typecho_remember_remember');
}
/** 截获验证异常 */
if ($error = $validator->run($this->request->from('name', 'password'))) {
@@ -56,7 +64,7 @@ class Login extends Users implements ActionInterface
$this->request->name,
$this->request->password,
false,
1 == $this->request->remember ? $this->options->time + $this->options->timezone + 30 * 24 * 3600 : 0
1 == $this->request->remember ? $expire : 0
);
/** 比对密码 */

View File

@@ -33,8 +33,7 @@ class Notice extends Widget
$this->highlight = $theId;
Cookie::set(
'__typecho_notice_highlight',
$theId,
Options::alloc()->time + Options::alloc()->timezone + 86400
$theId
);
}
@@ -52,10 +51,10 @@ class Notice extends Widget
* 设定堆栈每一行的值
*
* @param string|array $value 值对应的键值
* @param string $type 提示类型
* @param string|null $type 提示类型
* @param string $typeFix 兼容老插件
*/
public function set($value, string $type = 'notice', string $typeFix = 'notice')
public function set($value, ?string $type = 'notice', string $typeFix = 'notice')
{
$notice = is_array($value) ? array_values($value) : [$value];
if (empty($type) && $typeFix) {
@@ -64,13 +63,11 @@ class Notice extends Widget
Cookie::set(
'__typecho_notice',
json_encode($notice),
Options::alloc()->time + Options::alloc()->timezone + 86400
json_encode($notice)
);
Cookie::set(
'__typecho_notice_type',
$type,
Options::alloc()->time + Options::alloc()->timezone + 86400
$type
);
}
}

View File

@@ -87,6 +87,7 @@ RewriteRule ^(.*)$ {$basePath}index.php/$1 [L]
/** 发送一个rewrite地址请求 */
$client->setData(['do' => 'remoteCallback'])
->setHeader('User-Agent', $this->options->generator)
->setHeader('X-Requested-With', 'XMLHttpRequest')
->send(Common::url('/action/ajax', $this->options->siteUrl));
if (200 == $client->getResponseStatus() && 'OK' == $client->getResponseBody()) {
@@ -113,6 +114,7 @@ RewriteRule . {$basePath}index.php [L]
/** 发送一个rewrite地址请求 */
$client->setData(['do' => 'remoteCallback'])
->setHeader('User-Agent', $this->options->generator)
->setHeader('X-Requested-With', 'XMLHttpRequest')
->send(Common::url('/action/ajax', $this->options->siteUrl));
if (200 == $client->getResponseStatus() && 'OK' == $client->getResponseBody()) {

View File

@@ -268,7 +268,7 @@ class User extends Users
} else {
//防止循环重定向
$this->response->redirect(defined('__TYPECHO_ADMIN__') ? $this->options->loginUrl .
(0 === strpos($this->request->getReferer(), $this->options->loginUrl) ? '' :
(0 === strpos($this->request->getReferer() ?? '', $this->options->loginUrl) ? '' :
'?referer=' . urlencode($this->request->makeUriByRequest())) : $this->options->siteUrl, false);
}
}

View File

@@ -1532,7 +1532,7 @@ class XmlRpc extends Contents implements ActionInterface, Hook
[
'isAdmin' => $this->user->pass('administrator', true),
'url' => $this->options->siteUrl,
'blogid' => '1',
'blogid' => 1,
'blogName' => $this->options->title,
'xmlrpc' => $this->options->xmlRpcUrl
]
@@ -1897,7 +1897,9 @@ EOF;
}
/** 直接把初始化放到这里 */
new Server($api);
$server = new Server($api);
$server->setHook($this);
$server->serve();
}
}