Compare commits
40 Commits
v1.2.0-rc.
...
v1.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4be93f2741 | ||
|
|
6100695d87 | ||
|
|
0bdf8721e1 | ||
|
|
ce7af58367 | ||
|
|
1b673e06ff | ||
|
|
0edb48fae0 | ||
|
|
17fcb2f08b | ||
|
|
5f943d48b5 | ||
|
|
b23277267a | ||
|
|
b0d78a81dc | ||
|
|
f34d14280d | ||
|
|
13dc5e87dd | ||
|
|
0b021e5e7d | ||
|
|
00c75d2f75 | ||
|
|
1eedc481ad | ||
|
|
75899e287d | ||
|
|
047bd17f19 | ||
|
|
9c075dcdf0 | ||
|
|
157fc05265 | ||
|
|
c047669900 | ||
|
|
eee0228fed | ||
|
|
389b46635e | ||
|
|
919911e288 | ||
|
|
dd4bf889de | ||
|
|
0dcf45a152 | ||
|
|
ceaa545c7d | ||
|
|
01d9d0c3f5 | ||
|
|
6b46dd9c50 | ||
|
|
cb4457ab52 | ||
|
|
8a57b91343 | ||
|
|
c66b6e20ec | ||
|
|
b33a9c4d02 | ||
|
|
cac1c650a1 | ||
|
|
42e192340d | ||
|
|
b677f7db92 | ||
|
|
2fbc56dead | ||
|
|
d174cc5732 | ||
|
|
5557f6dd91 | ||
|
|
42fe6f7bf5 | ||
|
|
1f1019ba5b |
2
.github/workflows/Typecho-dev-Ci.yml
vendored
2
.github/workflows/Typecho-dev-Ci.yml
vendored
@@ -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
1
.gitignore
vendored
@@ -24,6 +24,7 @@
|
||||
*.sublime*
|
||||
.sass-cache
|
||||
config.rb
|
||||
prepros.config
|
||||
/config.inc.php
|
||||
/usr/uploads/
|
||||
/usr/*.db
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
<a href="http://docs.typecho.org"><?php _e('帮助文档'); ?></a> •
|
||||
<a href="http://forum.typecho.org"><?php _e('支持论坛'); ?></a> •
|
||||
<a href="https://github.com/typecho/typecho/issues"><?php _e('报告错误'); ?></a> •
|
||||
<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
@@ -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>
|
||||
|
||||
|
||||
@@ -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('« 取消筛选'); ?></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; ?>
|
||||
|
||||
@@ -36,7 +36,7 @@ $attachments = \Widget\Contents\Attachment\Admin::alloc();
|
||||
<a href="<?php $options->adminUrl('manage-medias.php'); ?>"><?php _e('« 取消筛选'); ?></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>
|
||||
|
||||
@@ -39,7 +39,7 @@ $pages = \Widget\Contents\Page\Admin::alloc();
|
||||
<a href="<?php $options->adminUrl('manage-pages.php'); ?>"><?php _e('« 取消筛选'); ?></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>
|
||||
|
||||
@@ -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('« 取消筛选'); ?></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); ?>
|
||||
|
||||
@@ -31,7 +31,7 @@ $users = \Widget\Users\Admin::alloc();
|
||||
<a href="<?php $options->adminUrl('manage-users.php'); ?>"><?php _e('« 取消筛选'); ?></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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]]);
|
||||
|
||||
@@ -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'; ?>
|
||||
|
||||
@@ -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"
|
||||
|
||||
36
install.php
36
install.php
@@ -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 大家族',
|
||||
|
||||
@@ -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') ?: '');
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,14 @@ class Db
|
||||
$this->adapter = new $adapterName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Adapter
|
||||
*/
|
||||
public function getAdapter(): Adapter
|
||||
{
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取适配器名称
|
||||
*
|
||||
|
||||
@@ -37,6 +37,13 @@ interface Adapter
|
||||
*/
|
||||
public function getVersion($handle): string;
|
||||
|
||||
/**
|
||||
* 获取数据库类型
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDriver(): string;
|
||||
|
||||
/**
|
||||
* 清空数据表
|
||||
*
|
||||
|
||||
@@ -29,4 +29,12 @@ trait MysqlTrait
|
||||
{
|
||||
return $this->buildQuery($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDriver(): string
|
||||
{
|
||||
return 'mysql';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -153,6 +153,14 @@ WHERE
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDriver(): string
|
||||
{
|
||||
return 'pgsql';
|
||||
}
|
||||
|
||||
abstract public function query(
|
||||
string $query,
|
||||
$handle,
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class SQLite implements Adapter
|
||||
*/
|
||||
public function getVersion($handle): string
|
||||
{
|
||||
return 'sqlite:sqlite ' . \SQLite3::version()['versionString'];
|
||||
return \SQLite3::version()['versionString'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,4 +99,12 @@ trait SQLiteTrait
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDriver(): string
|
||||
{
|
||||
return 'sqlite';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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] ?? '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +186,8 @@ class Response
|
||||
}
|
||||
|
||||
$this->redirect($referer);
|
||||
} elseif (!empty($default)) {
|
||||
$this->redirect($default);
|
||||
} else {
|
||||
$this->redirect($default ?: '/');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 . '"';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Widget;
|
||||
|
||||
use Typecho\Config;
|
||||
use Typecho\Db;
|
||||
use Typecho\Plugin;
|
||||
use Typecho\Widget;
|
||||
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/** 比对密码 */
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user