update install

This commit is contained in:
joyqi
2021-08-17 01:53:47 +08:00
parent bac7340c2a
commit 0d4299d99e
9 changed files with 502 additions and 201 deletions

View File

@@ -8,22 +8,22 @@
* @version $Id$
*/
/** 定义根目录 */
// site root path
define('__TYPECHO_ROOT_DIR__', dirname(__FILE__));
/** 定义插件目录(相对路径) */
// plugin directory (relative path)
define('__TYPECHO_PLUGIN_DIR__', '/usr/plugins');
/** 定义模板目录(相对路径) */
// theme directory (relative path)
define('__TYPECHO_THEME_DIR__', '/usr/themes');
/** 后台路径(相对路径) */
// admin directory (relative path)
define('__TYPECHO_ADMIN_DIR__', '/admin/');
/** 载入API支持 */
// register autoload
require_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';
/** 程序初始化 */
// init
Typecho_Common::init();
else:
@@ -35,8 +35,7 @@ else:
try {
$installed = $db->fetchRow($db->select()->from('table.options')->where('name = ?', 'installed'));
if (empty($installed) || $installed['value'] == 1) {
Typecho_Response::setStatus(404);
exit;
exit(1);
}
} catch (Exception $e) {
// do nothing
@@ -47,13 +46,15 @@ endif;
define('__TYPECHO_INSTALL__', true);
/**
* 获取系统语言
* get lang
*
* @return string
*/
function install_get_lang(): string {
if (isset($_SERVER['TYPECHO_LANG'])) {
return $_SERVER['TYPECHO_LANG'];
$serverLang = Typecho_Request::getInstance()->getServer('TYPECHO_LANG');
if (!empty($serverLang)) {
return $serverLang;
} else {
$lang = 'zh_CN';
$request = Typecho_Request::getInstance();
@@ -68,13 +69,15 @@ function install_get_lang(): string {
}
/**
* 获取站点地址
* get site url
*
* @return string
*/
function install_get_site_url(): string {
if (isset($_SERVER['TYPECHO_SITE_URL'])) {
return $_SERVER['TYPECHO_SITE_URL'];
$serverSiteUrl = Typecho_Request::getInstance()->getServer('TYPECHO_SITE_URL');
if (!empty($serverSiteUrl)) {
return $serverSiteUrl;
} else {
$request = Typecho_Request::getInstance();
return $request->get('userUrl', $request->getRequestRoot());
@@ -82,7 +85,16 @@ function install_get_site_url(): string {
}
/**
* 获取默认参数
* detect cli mode
*
* @return bool
*/
function install_is_cli(): bool {
return php_sapi_name() == 'cli';
}
/**
* list all default options
*
* @return array
*/
@@ -153,7 +165,18 @@ function install_get_default_options(): array {
}
/**
* 获取所有可用数据库驱动
* get database driver type
*
* @param string $driver
* @return string
*/
function install_get_db_type(string $driver): string {
$parts = explode('_', $driver);
return $driver == 'Mysqli' ? 'Mysql' : array_pop($parts);
}
/**
* list all available database drivers
*
* @return array
*/
@@ -187,6 +210,68 @@ function install_get_db_drivers(): array {
return $drivers;
}
/**
* generate config file
*
* @param string $adapter
* @param string $dbPrefix
* @param array $dbConfig
* @return string
*/
function install_config_file(string $adapter, string $dbPrefix, array $dbConfig): string {
$lines = array_slice(file(__FILE__), 1, 26);
$lines[] = "
/** 定义数据库参数 */
\$db = new Typecho_Db('{$adapter}', '{$dbPrefix}');
\$db->addServer(" . (var_export($dbConfig, true)) . ", Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set(\$db);
";
return implode('', $lines);
}
/**
* raise install error
*
* @param mixed $error
* @param mixed $config
*/
function install_raise_error($error, $config = null) {
$lines = [];
if (is_array($error)) {
foreach ($error as $key => $value) {
$lines[] = $key . ': ' . $value;
}
} else {
$lines[] = $error;
}
if (install_is_cli()) {
echo implode("\n", $lines);
exit(1);
} else {
Typecho_Response::getInstance()->throwJson([
'success' => 0,
'message' => implode("<br>", $lines),
'config' => $config
]);
}
}
/**
* @param $step
*/
function install_success($step) {
if (install_is_cli()) {
$method = 'install_step_' . $step . '_perform';
$method();
} else {
Typecho_Response::getInstance()->throwJson([
'success' => $step
]);
}
}
function install_ajax_support() {
?>
<script>
@@ -200,6 +285,8 @@ function install_ajax_support() {
errorBox.innerHTML = str.replace('%', error);
errorBox.classList.remove('hidden');
return errorBox;
}
form.addEventListener('submit', function (e) {
@@ -219,7 +306,11 @@ function install_ajax_support() {
showError(data.message);
}
}).catch(function (error) {
showError(error.message);
let el = showError(error.message);
if (typeof configError == 'function' && error.config) {
configError(error.config, el);
}
});
}, true);
</script>
@@ -255,33 +346,272 @@ function install_step_1() {
<?php
}
/**
* check step 2
*/
function install_step_2_check(): bool {
return !file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php');
}
/**
* display step 2
*/
function install_step_2() {
$drivers = install_get_db_drivers();
$adapter = _r('driver', key($drivers));
$parts = explode('_', $adapter);
$type = $adapter == 'Mysqli' ? 'Mysql' : array_pop($parts);
$adapter = Typecho_Request::getInstance()->get('driver', key($drivers));
$type = install_get_db_type($adapter);
?>
<ul class="typecho-option">
<li>
<label for="dbAdapter" class="typecho-label"><?php _e('数据库适配器'); ?></label>
<select name="dbAdapter" id="dbAdapter" onchange="location.href='?step=2&driver=' + this.value">
<?php foreach ($drivers as $driver => $name): ?>
<option value="<?php echo $driver; ?>"<?php if($driver == $adapter): ?> selected="selected"<?php endif; ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
<p class="description"><?php _e('请根据您的数据库类型选择合适的适配器'); ?></p>
</li>
<?php require_once './install/' . $type . '.php'; ?>
<li>
<label class="typecho-label" for="dbPrefix"><?php _e('数据库前缀'); ?></label>
<input type="text" class="text" name="dbPrefix" id="dbPrefix" value="<?php _v('dbPrefix', 'typecho_'); ?>" />
<p class="description"><?php _e('默认前缀是 "typecho_"'); ?></p>
</li>
</ul>
<form action="?step=2" method="post">
<ul class="typecho-option">
<li>
<label for="dbAdapter" class="typecho-label"><?php _e('数据库适配器'); ?></label>
<select name="dbAdapter" id="dbAdapter" onchange="location.href='?step=2&driver=' + this.value">
<?php foreach ($drivers as $driver => $name): ?>
<option value="<?php echo $driver; ?>"<?php if($driver == $adapter): ?> selected="selected"<?php endif; ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
<p class="description"><?php _e('请根据您的数据库类型选择合适的适配器'); ?></p>
<input type="hidden" id="dbNext" name="dbNext" value="none">
</li>
<?php require_once './install/' . $type . '.php'; ?>
<li>
<label class="typecho-label" for="dbPrefix"><?php _e('数据库前缀'); ?></label>
<input type="text" class="text" name="dbPrefix" id="dbPrefix" value="<?php _v('dbPrefix', 'typecho_'); ?>" />
<p class="description"><?php _e('默认前缀是 "typecho_"'); ?></p>
</li>
</ul>
</form>
<script>
function configError(config, errorBox) {
let next = document.querySelector('#dbNext'),
line = document.createElement('p'),
form = document.querySelector('form');
errorBox.appendChild(line);
config.forEach(function (word, key) {
let btn = document.createElement('button');
btn.innerHTML = word;
btn.addEventListener('click', function () {
next.setAttribute('value', key);
});
line.appendChild(btn);
form.submit();
});
}
</script>
<?php
install_ajax_support();
}
function install_step_2_perform() {
$request = Typecho_Request::getInstance();
$drivers = install_get_db_drivers();
$configMap = [
'Mysql' => [
'dbHost' => 'localhost',
'dbPort' => 3306,
'dbUser' => null,
'dbPassword' => null,
'dbCharset' => 'utf8mb4',
'dbDatabase' => null,
'dbEngine' => 'InnoDB'
],
'Pgsql' => [
'dbHost' => 'localhost',
'dbPort' => 5432,
'dbUser' => null,
'dbPassword' => null,
'dbCharset' => 'utf8',
'dbDatabase' => null,
],
'SQLite' => [
'dbFile' => __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'
]
];
if (install_is_cli()) {
$config = [
'dbHost' => $request->getServer('TYPECHO_DB_HOST'),
'dbUser' => $request->getServer('TYPECHO_DB_USER'),
'dbPassword' => $request->getServer('TYPECHO_DB_PASSWORD'),
'dbCharset' => $request->getServer('TYPECHO_DB_CHARSET'),
'dbPort' => $request->getServer('TYPECHO_DB_PORT'),
'dbDatabase' => $request->getServer('TYPECHO_DB_DATABASE'),
'dbFile' => $request->getServer('TYPECHO_DB_FILE'),
'dbDsn' => $request->getServer('TYPECHO_DB_DSN'),
'dbEngine' => $request->getServer('TYPECHO_DB_ENGINE'),
'dbPrefix' => $request->getServer('TYPECHO_DB_PREFIX'),
'dbAdapter' => $request->getServer('TYPECHO_DB_ADAPTER'),
'dbNext' => $request->getServer('TYPECHO_DB_NEXT', 'none')
];
} else {
$config = $request->from([
'dbHost',
'dbUser',
'dbPassword',
'dbCharset',
'dbPort',
'dbDatabase',
'dbFile',
'dbDsn',
'dbEngine',
'dbPrefix',
'dbAdapter',
'dbNext'
]);
}
$error = (new Typecho_Validate())
->addRule('dbPrefix', 'required', _t('确认您的配置'))
->addRule('dbPrefix', 'minLength', _t('确认您的配置'), 1)
->addRule('dbPrefix', 'maxLength', _t('确认您的配置'), 16)
->addRule('dbPrefix', 'alphaDash', _t('确认您的配置'))
->addRule('dbAdapter', 'required', _t('确认您的配置'))
->addRule('dbAdapter', 'enum', _t('确认您的配置'), array_keys($drivers))
->addRule('dbNext', 'required', _t('确认您的配置'))
->addRule('dbNext', 'enum', _t('确认您的配置'), ['none', 'delete', 'keep'])
->run($config);
if (!empty($error)) {
install_raise_error($error);
}
$type = install_get_db_type($config['dbAdapter']);
$dbConfig = [];
foreach ($configMap[$type] as $key => $value) {
$dbConfig[strtolower(substr($key, 2))]
= $config[$key] === null ? (install_is_cli() ? $value : null) : $config[$key];
}
switch ($type) {
case 'Mysql':
$error = (new Typecho_Validate())
->addRule('host', 'required', _t('确认您的配置'))
->addRule('port', 'required', _t('确认您的配置'))
->addRule('port', 'isInteger', _t('确认您的配置'))
->addRule('user', 'required', _t('确认您的配置'))
->addRule('charset', 'required', _t('确认您的配置'))
->addRule('charset', 'enum', _t('确认您的配置'), ['utf8', 'utf8mb4'])
->addRule('database', 'required', _t('确认您的配置'))
->addRule('engine', 'required', _t('确认您的配置'))
->addRule('engine', 'enum', _t('确认您的配置'), ['InnoDB', 'MyISAM'])
->run($dbConfig);
break;
case 'Pgsql':
$error = (new Typecho_Validate())
->addRule('host', 'required', _t('确认您的配置'))
->addRule('port', 'required', _t('确认您的配置'))
->addRule('port', 'isInteger', _t('确认您的配置'))
->addRule('user', 'required', _t('确认您的配置'))
->addRule('charset', 'required', _t('确认您的配置'))
->addRule('charset', 'enum', _t('确认您的配置'), ['utf8'])
->addRule('database', 'required', _t('确认您的配置'))
->run($dbConfig);
break;
case 'SQLite':
$error = (new Typecho_Validate())
->addRule('file', 'required', _t('确认您的配置'))
->run($dbConfig);
break;
default:
install_raise_error(_t('确认您的配置'));
break;
}
if (!empty($error)) {
install_raise_error($error);
}
// detect db config
try {
$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) {
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装'));
} catch (Typecho_Db_Exception $e) {
install_raise_error(_t('安装程序捕捉到以下错误: " %s ". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
}
if (!isset($installDb)) {
return;
}
// delete exists db
if($config['dbNext'] == 'delete') {
$tables = [
$config['dbPrefix'] . 'comments',
$config['dbPrefix'] . 'contents',
$config['dbPrefix'] . 'fields',
$config['dbPrefix'] . 'metas',
$config['dbPrefix'] . 'options',
$config['dbPrefix'] . 'relationships',
$config['dbPrefix'] . 'users'
];
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}");
}
}
} catch (Typecho_Db_Exception $e) {
install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
}
}
// init db structure
try {
$scripts = file_get_contents(__TYPECHO_ROOT_DIR__ . '/install/' . $type . '.sql');
$scripts = str_replace('typecho_', $config['dbPrefix'], $scripts);
if (isset($dbConfig['charset'])) {
$scripts = str_replace('%charset%', $dbConfig['charset'], $scripts);
}
if (isset($dbConfig['engine'])) {
$scripts = str_replace('%engine%', $dbConfig['engine'], $scripts);
}
$scripts = explode(';', $scripts);
foreach ($scripts as $script) {
$script = trim($script);
if ($script) {
$installDb->query($script, Typecho_Db::WRITE);
}
}
} catch (Typecho_Db_Exception $e) {
$code = $e->getCode();
if(('Mysql' == $type && (1050 == $code || '42S01' == $code)) ||
('SQLite' == $type && ('HY000' == $code || 1 == $code)) ||
('Pgsql' == $type && '42P07' == $code)) {
if ($config['dbNext'] == 'keep') {
install_success(3);
} elseif ($config['dbNext' == 'none']) {
install_raise_error(_t('安装程序检查到原有数据表已经存在.'), [
'delete' => _t('删除原有数据'),
'keep' => _t('使用原有数据')
]);
}
} else {
install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
}
}
install_success(3);
}
$options = Typecho_Widget::widget('Widget_Options', install_get_default_options());
Typecho_Widget::widget('Widget_Init');

View File

@@ -2,34 +2,34 @@
<li>
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
<input type="text" class="text" name="dbHost" id="dbHost" value="<?php _v('dbHost', 'localhost'); ?>"/>
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="<?php _v('dbPort', '3306'); ?>"/>
<input type="text" class="text" name="dbPort" id="dbPort" value="3306"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
<input type="text" class="text" name="dbUser" id="dbUser" value="<?php _v('dbUser', 'root'); ?>" />
<input type="text" class="text" name="dbUser" id="dbUser" value="" />
<p class="description"><?php _e('您可能会使用 "%s"', 'root'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
<input type="password" class="text" name="dbPassword" id="dbPassword" value="<?php _v('dbPassword'); ?>" />
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
</li>
<li>
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="<?php _v('dbDatabase', 'typecho'); ?>" />
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbCharset"><?php _e('数据库编码'); ?></label>
<select name="dbCharset" id="dbCharset">
<option value="utf8mb4"<?php if (_r('dbCharset') == 'utf8mb4'): ?> selected<?php endif; ?>>utf8mb4</option>
<option value="utf8"<?php if (_r('dbCharset') == 'utf8'): ?> selected<?php endif; ?>>utf8</option>
<option value="utf8mb4">utf8mb4</option>
<option value="utf8">utf8</option>
</select>
<p class="description"><?php _e('选择 utf8mb4 编码至少需要 MySQL 5.5.3 版本'); ?></p>
</li>
@@ -37,7 +37,7 @@
<li>
<label class="typecho-label" for="dbEngine"><?php _e('数据库引擎'); ?></label>
<select name="dbEngine" id="dbEngine">
<option value="InnoDB"<?php if (_r('dbEngine') == 'InnoDB'): ?> selected<?php endif; ?>>InnoDB</option>
<option value="MyISAM"<?php if (_r('dbEngine') == 'MyISAM'): ?> selected<?php endif; ?>>MyISAM</option>
<option value="InnoDB">InnoDB</option>
<option value="MyISAM">MyISAM</option>
</select>
</li>

View File

@@ -1,26 +1,26 @@
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<li>
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
<input type="text" class="text" name="dbHost" id="dbHost" value="<?php _v('dbHost', 'localhost'); ?>"/>
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="<?php _v('dbPort', '5432'); ?>"/>
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
<input type="text" class="text" name="dbUser" id="dbUser" value="<?php _v('dbUser', 'postgres'); ?>" />
<input type="text" class="text" name="dbUser" id="dbUser" value="postgres" />
<p class="description"><?php _e('您可能会使用 "%s"', 'postgres'); ?></p>
</li>
<li>
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
<input type="password" class="text" name="dbPassword" id="dbPassword" value="<?php _v('dbPassword'); ?>" />
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
</li>
<li>
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="<?php _v('dbDatabase', 'typecho'); ?>" />
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
</li>
<input type="hidden" name="dbCharset" value="<?php _e('utf8'); ?>" />
<input type="hidden" name="dbCharset" value="utf8" />

View File

@@ -2,6 +2,6 @@
<?php $defaultDir = __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'; ?>
<li>
<label class="typecho-label" for="dbFile"><?php _e('数据库文件路径'); ?></label>
<input type="text" class="text" name="dbFile" id="dbFile" value="<?php _v('dbFile', $defaultDir); ?>"/>
<input type="text" class="text" name="dbFile" id="dbFile" value="<?php echo $defaultDir; ?>"/>
<p class="description"><?php _e('"%s" 是我们为您自动生成的地址', $defaultDir); ?></p>
</li>

View File

@@ -94,7 +94,7 @@ class Typecho_Request
* @access private
* @var Typecho_Request
*/
private static $_instance = null;
private static $_instance;
/**
* 全部的http数据
@@ -140,9 +140,9 @@ class Typecho_Request
* @access public
* @return Typecho_Request
*/
public static function getInstance()
public static function getInstance(): Typecho_Request
{
if (null === self::$_instance) {
if (!isset(self::$_instance)) {
self::$_instance = new Typecho_Request();
}
@@ -179,7 +179,7 @@ class Typecho_Request
*
* @return boolean
*/
private function _checkIp($ip)
private function _checkIp(string $ip): bool
{
if (__TYPECHO_FILTER_SUPPORTED__) {
return false !== (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
@@ -197,7 +197,7 @@ class Typecho_Request
*
* @return boolean
*/
private function _checkAgent($agent)
private function _checkAgent(string $agent): bool
{
return preg_match("/^[_a-z0-9- ,:;=#@\.\(\)\/\+\*\?]+$/i", $agent);
}
@@ -219,14 +219,14 @@ class Typecho_Request
* @access public
* @return string
*/
public function getUrlPrefix()
public function getUrlPrefix(): string
{
if (empty($this->_urlPrefix)) {
if (defined('__TYPECHO_URL_PREFIX__')) {
$this->_urlPrefix = __TYPECHO_URL_PREFIX__;
} else if (!defined('__TYPECHO_CLI__')) {
$this->_urlPrefix = ($this->isSecure() ? 'https' : 'http') . '://'
. (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']);
. ($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME']);
}
}
@@ -239,7 +239,7 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isSecure()
public function isSecure(): bool
{
return (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && !strcasecmp('https', $_SERVER['HTTP_X_FORWARDED_PROTO']))
|| (!empty($_SERVER['HTTP_X_FORWARDED_PORT']) && 443 == $_SERVER['HTTP_X_FORWARDED_PORT'])
@@ -254,7 +254,7 @@ class Typecho_Request
* @access public
* @return Typecho_Request
*/
public function filter()
public function filter(): Typecho_Request
{
$filters = func_get_args();
@@ -275,7 +275,7 @@ class Typecho_Request
*
* @return mixed
*/
public function __get($key)
public function __get(string $key)
{
return $this->get($key);
}
@@ -289,7 +289,7 @@ class Typecho_Request
*
* @return boolean
*/
public function __isset($key)
public function __isset(string $key)
{
return isset(self::$_httpParams[$key])
|| isset($this->_params[$key]);
@@ -305,7 +305,7 @@ class Typecho_Request
*
* @return mixed
*/
public function get($key, $default = null)
public function get(string $key, $default = null)
{
switch (true) {
case isset($this->_params[$key]):
@@ -330,10 +330,9 @@ class Typecho_Request
*
* @return array
*/
public function getArray($key)
public function getArray($key): array
{
$result = isset($this->_params[$key]) ? $this->_params[$key] :
(isset(self::$_httpParams[$key]) ? self::$_httpParams[$key] : []);
$result = $this->_params[$key] ?? (self::$_httpParams[$key] ?? []);
$result = is_array($result) ? $result
: (strlen($result) > 0 ? [$result] : []);
@@ -349,7 +348,7 @@ class Typecho_Request
*
* @return array
*/
public function from($params)
public function from($params): array
{
$result = [];
$args = is_array($params) ? $params : func_get_args();
@@ -371,7 +370,7 @@ class Typecho_Request
*
* @return void
*/
public function setParam($name, $value)
public function setParam(string $name, $value)
{
if (Typecho_Common::checkStrEncoding($value)) {
$this->_params[$name] = $value;
@@ -405,7 +404,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getRequestRoot()
public function getRequestRoot(): string
{
if (null === $this->_requestRoot) {
$root = rtrim($this->getUrlPrefix() . $this->getBaseUrl(), '/') . '/';
@@ -427,7 +426,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getRequestUrl()
public function getRequestUrl(): string
{
return $this->getUrlPrefix() . $this->getRequestUri();
}
@@ -438,7 +437,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getRequestUri()
public function getRequestUri(): ?string
{
if (!empty($this->_requestUri)) {
return $this->_requestUri;
@@ -486,7 +485,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getBaseUrl()
public function getBaseUrl(): ?string
{
if (null !== $this->_baseUrl) {
return $this->_baseUrl;
@@ -504,8 +503,8 @@ class Typecho_Request
} else {
// Backtrack up the script_filename to find the portion matching
// php_self
$path = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '';
$file = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : '';
$path = $_SERVER['PHP_SELF'] ?? '';
$file = $_SERVER['SCRIPT_FILENAME'] ?? '';
$segs = explode('/', trim($file, '/'));
$segs = array_reverse($segs);
$index = 0;
@@ -551,7 +550,7 @@ class Typecho_Request
*
* @return string
*/
public function makeUriByRequest($parameter = null)
public function makeUriByRequest($parameter = null): string
{
/** 初始化地址 */
$requestUri = $this->getRequestUrl();
@@ -582,12 +581,12 @@ class Typecho_Request
*
* @access public
*
* @param string $inputEncoding 输入编码
* @param string $outputEncoding 输出编码
* @param string|null $inputEncoding 输入编码
* @param string|null $outputEncoding 输出编码
*
* @return string
*/
public function getPathInfo($inputEncoding = null, $outputEncoding = null)
public function getPathInfo(string $inputEncoding = null, string $outputEncoding = null): ?string
{
/** 缓存信息 */
if (null !== $this->_pathInfo) {
@@ -634,45 +633,19 @@ class Typecho_Request
return ($this->_pathInfo = '/' . ltrim(urldecode($pathInfo), '/'));
}
/**
* 设置服务端参数
*
* @access public
*
* @param string $name 参数名称
* @param mixed $value 参数值
*
* @return void
*/
public function setServer($name, $value = null)
{
if (null == $value) {
if (isset($_SERVER[$name])) {
$value = $_SERVER[$name];
} else if (isset($_ENV[$name])) {
$value = $_ENV[$name];
}
}
$this->_server[$name] = $value;
}
/**
* 获取环境变量
*
* @access public
*
* @param string $name 获取环境变量名
* @param string|null $default
*
* @return string
* @return string|null
*/
public function getServer($name)
public function getServer(string $name, string $default = null): ?string
{
if (!isset($this->_server[$name])) {
$this->setServer($name);
}
return $this->_server[$name];
return $_SERVER[$name] ?? $default;
}
/**
@@ -680,16 +653,21 @@ class Typecho_Request
*
* @access public
*
* @param string $ip
* @param string|null $ip
*/
public function setIp($ip = null)
public function setIp(string $ip = null)
{
if (!empty($ip)) {
$this->_ip = $ip;
} else {
switch (true) {
case defined('__TYPECHO_IP_SOURCE__') && null !== $this->getServer(__TYPECHO_IP_SOURCE__):
list($this->_ip) = array_map('trim', explode(',', $this->getServer(__TYPECHO_IP_SOURCE__)));
case defined('__TYPECHO_IP_SOURCE__')
&& null !== $this->getServer(__TYPECHO_IP_SOURCE__):
list($this->_ip) = array_map(
'trim',
explode(',',
$this->getServer(__TYPECHO_IP_SOURCE__))
);
break;
case null !== $this->getServer('REMOTE_ADDR'):
$this->_ip = $this->getServer('REMOTE_ADDR');
@@ -713,7 +691,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getIp()
public function getIp(): string
{
if (null === $this->_ip) {
$this->setIp();
@@ -727,11 +705,11 @@ class Typecho_Request
*
* @access public
*
* @param string $agent 客户端字符串
* @param string|null $agent 客户端字符串
*
* @return void
*/
public function setAgent($agent = null)
public function setAgent(string $agent = null)
{
$agent = (null === $agent) ? $this->getServer('HTTP_USER_AGENT') : $agent;
$this->_agent = self::_checkAgent($agent) ? $agent : '';
@@ -743,7 +721,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getAgent()
public function getAgent(): ?string
{
if (null === $this->_agent) {
$this->setAgent();
@@ -757,11 +735,11 @@ class Typecho_Request
*
* @access public
*
* @param string $referer 客户端字符串
* @param string|null $referer 客户端字符串
*
* @return void
*/
public function setReferer($referer = null)
public function setReferer(string $referer = null)
{
$this->_referer = (null === $referer) ? $this->getServer('HTTP_REFERER') : $referer;
}
@@ -772,7 +750,7 @@ class Typecho_Request
* @access public
* @return string
*/
public function getReferer()
public function getReferer(): string
{
if (null === $this->_referer) {
$this->setReferer();
@@ -787,7 +765,7 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isGet()
public function isGet(): bool
{
return 'GET' == $this->getServer('REQUEST_METHOD');
}
@@ -798,7 +776,7 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isPost()
public function isPost(): bool
{
return 'POST' == $this->getServer('REQUEST_METHOD');
}
@@ -809,7 +787,7 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isPut()
public function isPut(): bool
{
return 'PUT' == $this->getServer('REQUEST_METHOD');
}
@@ -820,7 +798,7 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isAjax()
public function isAjax(): bool
{
return 'XMLHttpRequest' == $this->getServer('HTTP_X_REQUESTED_WITH');
}
@@ -831,24 +809,11 @@ class Typecho_Request
* @access public
* @return boolean
*/
public function isFlash()
public function isFlash(): bool
{
return 'Shockwave Flash' == $this->getServer('USER_AGENT');
}
/**
* isMobile
*
* @static
* @access public
* @return boolean
*/
public function isMobile()
{
$userAgent = $this->getAgent();
return preg_match('/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $userAgent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($userAgent, 0, 4));
}
/**
* 判断输入是否满足要求
*
@@ -858,7 +823,7 @@ class Typecho_Request
*
* @return boolean
*/
public function is($query)
public function is($query): bool
{
$validated = false;
@@ -870,7 +835,7 @@ class Typecho_Request
}
/** 验证串 */
if ($params) {
if (!empty($params)) {
$validated = true;
foreach ($params as $key => $val) {
$validated = empty($val) ? $this->__isset($key) : ($val == $this->get($key));

View File

@@ -25,7 +25,7 @@ class Typecho_Response
* @access private
* @var array
*/
private static $_httpCode = array(
private static $_httpCode = [
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
@@ -66,7 +66,7 @@ class Typecho_Response
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported'
);
];
/**
* 字符编码
@@ -85,14 +85,14 @@ class Typecho_Response
* @access private
* @var Typecho_Response
*/
private static $_instance = null;
private static $_instance;
/**
* 结束前回调函数
*
* @var array
*/
private static $_callbacks = array();
private static $_callbacks = [];
/**
* 获取单例句柄
@@ -100,9 +100,9 @@ class Typecho_Response
* @access public
* @return Typecho_Response
*/
public static function getInstance()
public static function getInstance(): Typecho_Response
{
if (null === self::$_instance) {
if (!isset(self::$_instance)) {
self::$_instance = new Typecho_Response();
}
@@ -116,7 +116,7 @@ class Typecho_Response
* @param mixed $message 格式化数据
* @return string
*/
private function _parseXml($message)
private function _parseXml($message): string
{
/** 对于数组型则继续递归 */
if (is_array($message)) {
@@ -164,10 +164,10 @@ class Typecho_Response
* 设置默认回执编码
*
* @access public
* @param string $charset 字符集
* @param string|null $charset 字符集
* @return void
*/
public function setCharset($charset = null)
public function setCharset(string $charset = null)
{
$this->_charset = empty($charset) ? self::CHARSET : $charset;
}
@@ -178,7 +178,7 @@ class Typecho_Response
* @access public
* @return string
*/
public function getCharset()
public function getCharset(): string
{
if (empty($this->_charset)) {
$this->setCharset();
@@ -194,7 +194,7 @@ class Typecho_Response
* @param string $contentType 文档类型
* @return void
*/
public function setContentType($contentType = 'text/html')
public function setContentType(string $contentType = 'text/html')
{
header('Content-Type: ' . $contentType . '; charset=' . $this->getCharset(), true);
}
@@ -207,7 +207,7 @@ class Typecho_Response
* @param string $value 对应值
* @return void
*/
public function setHeader($name, $value)
public function setHeader(string $name, string $value)
{
header($name . ': ' . $value, true);
}
@@ -219,10 +219,11 @@ class Typecho_Response
* @param integer $code http代码
* @return void
*/
public static function setStatus($code)
public static function setStatus(int $code)
{
if (isset(self::$_httpCode[$code])) {
header((isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1') . ' ' . $code . ' ' . self::$_httpCode[$code], true, $code);
header(($_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1')
. ' ' . $code . ' ' . self::$_httpCode[$code], true, $code);
}
}
@@ -233,7 +234,7 @@ class Typecho_Response
* @param string $message 消息体
* @return void
*/
public function throwXml($message)
public function throwXml(string $message)
{
/** 设置http头信息 */
$this->setContentType('text/xml');
@@ -276,33 +277,33 @@ class Typecho_Response
* @param boolean $isPermanently 是否为永久重定向
* @return void
*/
public function redirect($location, $isPermanently = false)
public function redirect(string $location, bool $isPermanently = false)
{
/** Typecho_Common */
$location = Typecho_Common::safeUrl($location);
self::callback();
if ($isPermanently) {
self::callback();
header('Location: ' . $location, false, 301);
exit;
} else {
self::callback();
header('Location: ' . $location, false, 302);
exit;
}
exit;
}
/**
* 返回来路
*
* @access public
* @param string $suffix 附加地址
* @param string $default 默认来路
* @param string|null $suffix 附加地址
* @param string|null $default 默认来路
*/
public function goBack($suffix = NULL, $default = NULL)
public function goBack(string $suffix = null, string $default = null)
{
//获取来源
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
$referer = $_SERVER['HTTP_REFERER'] ?? '';
//判断来源
if (!empty($referer)) {
@@ -316,7 +317,7 @@ class Typecho_Response
}
if (isset($myParts['query'])) {
$args = array();
$args = [];
if (isset($parts['query'])) {
parse_str($parts['query'], $args);
}

View File

@@ -62,16 +62,16 @@ class Typecho_Validate
* @param string $key 数值键值
* @param string $rule 规则名称
* @param string $message 错误字符串
* @return Typecho_Validation
* @return $this
*/
public function addRule($key, $rule, $message)
public function addRule(string $key, string $rule, string $message): Typecho_Validate
{
if (func_num_args() <= 3) {
$this->_rules[$key][] = array($rule, $message);
$this->_rules[$key][] = [$rule, $message];
} else {
$params = func_get_args();
$params = array_splice($params, 3);
$this->_rules[$key][] = array_merge(array($rule, $message), $params);
$this->_rules[$key][] = array_merge([$rule, $message], $params);
}
return $this;
@@ -94,13 +94,12 @@ class Typecho_Validate
*
* @access public
* @param array $data 需要验证的数据
* @param array $rules 验证数据遵循的规则
* @param array|null $rules 验证数据遵循的规则
* @return array
* @throws Typecho_Validate_Exception
*/
public function run(array $data, $rules = NULL)
public function run(array $data, array $rules = null): array
{
$result = array();
$result = [];
$this->_data = $data;
$rules = empty($rules) ? $this->_rules : $rules;
@@ -108,7 +107,7 @@ class Typecho_Validate
foreach ($rules as $key => $rules) {
$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 ($rules as $params) {
$method = $params[0];
@@ -121,7 +120,7 @@ class Typecho_Validate
$params[1] = $data[$key];
$params = array_slice($params, 1);
if (!call_user_func_array(is_array($method) ? $method : array($this, $method), $params)) {
if (!call_user_func_array(is_array($method) ? $method : [$this, $method], $params)) {
$result[$key] = $message;
break;
}
@@ -144,7 +143,7 @@ class Typecho_Validate
* @param integer $length 最小长度
* @return boolean
*/
public static function minLength($str, $length)
public static function minLength(string $str, int $length): bool
{
return (Typecho_Common::strLen($str) >= $length);
}
@@ -153,11 +152,11 @@ class Typecho_Validate
* 验证输入是否一致
*
* @access public
* @param string $str 待处理的字符串
* @param string|null $str 待处理的字符串
* @param string $key 需要一致性检查的键值
* @return boolean
*/
public function confirm($str, $key)
public function confirm(?string $str, string $key): bool
{
return !empty($this->_data[$key]) ? ($str == $this->_data[$key]) : empty($str);
}
@@ -169,7 +168,7 @@ class Typecho_Validate
* @param string $str 待处理的字符串
* @return boolean
*/
public function required($str)
public function required(string $str): bool
{
return !empty($this->_data[$this->_key]);
}
@@ -180,9 +179,9 @@ class Typecho_Validate
* @access public
* @param string $str 待处理的字符串
* @param array $params 枚举值
* @return unknown
* @return bool
*/
public static function enum($str, array $params)
public static function enum(string $str, array $params): bool
{
$keys = array_flip($params);
return isset($keys[$str]);
@@ -191,11 +190,11 @@ class Typecho_Validate
/**
* Max Length
*
* @param $str
* @param $length
* @param string $str
* @param int $length
* @return bool
*/
public static function maxLength($str, $length)
public static function maxLength(string $str, int $length): bool
{
return (Typecho_Common::strLen($str) < $length);
}
@@ -204,10 +203,10 @@ class Typecho_Validate
* Valid Email
*
* @access public
* @param string
* @param string $str
* @return boolean
*/
public static function email($str)
public static function email(string $str): bool
{
return preg_match("/^[_a-z0-9-\.+]+@([-a-z0-9]+\.)+[a-z]{2,}$/i", $str);
}
@@ -219,7 +218,7 @@ class Typecho_Validate
* @param string $str
* @return boolean
*/
public static function url($str)
public static function url(string $str): bool
{
$parts = @parse_url($str);
if (!$parts) {
@@ -227,8 +226,8 @@ class Typecho_Validate
}
return isset($parts['scheme']) &&
in_array($parts['scheme'], array('http', 'https', 'ftp')) &&
!preg_match('/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', $str);
in_array($parts['scheme'], ['http', 'https', 'ftp']) &&
!preg_match('/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', $str);
}
/**
@@ -238,7 +237,7 @@ class Typecho_Validate
* @param string
* @return boolean
*/
public static function alpha($str)
public static function alpha(string $str): bool
{
return preg_match("/^([a-z])+$/i", $str) ? true : false;
}
@@ -250,7 +249,7 @@ class Typecho_Validate
* @param string
* @return boolean
*/
public static function alphaNumeric($str)
public static function alphaNumeric(string $str): bool
{
return preg_match("/^([a-z0-9])+$/i", $str);
}
@@ -262,7 +261,7 @@ class Typecho_Validate
* @param string
* @return boolean
*/
public static function alphaDash($str)
public static function alphaDash(string $str): bool
{
return preg_match("/^([_a-z0-9-])+$/i", $str) ? true : false;
}
@@ -274,7 +273,7 @@ class Typecho_Validate
* @param string $str
* @return boolean
*/
public static function xssCheck($str)
public static function xssCheck(string $str): bool
{
$search = 'abcdefghijklmnopqrstuvwxyz';
$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
@@ -298,10 +297,10 @@ class Typecho_Validate
* Numeric
*
* @access public
* @param integer
* @param mixed $str
* @return boolean
*/
public static function isFloat($str)
public static function isFloat($str): bool
{
return preg_match("/^[0-9\.]+$/", $str);
}
@@ -310,10 +309,10 @@ class Typecho_Validate
* Is Numeric
*
* @access public
* @param string
* @param mixed $str
* @return boolean
*/
public static function isInteger($str)
public static function isInteger($str): bool
{
return is_numeric($str);
}

View File

@@ -361,8 +361,14 @@ class Widget_Options extends Typecho_Widget
public function execute()
{
if (!empty($this->db)) {
$this->db->fetchAll($this->db->select()->from('table.options')
$values = $this->db->fetchAll($this->db->select()->from('table.options')
->where('user = 0'), array($this, 'push'));
// finish install
if (empty($values)) {
$this->response->redirect(defined('__TYPECHO_ADMIN__')
? '../install.php?step=3' : 'install.php?step=3');
}
}
/** 支持皮肤变量重载 */

View File

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