added auto-updating

This commit is contained in:
printempw 2016-04-03 21:49:19 +08:00
parent cc1c3f5668
commit 9749393cc0
18 changed files with 388 additions and 152 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
textures/*
config.php
.phpintel/
setup/update_cache/*

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-19 21:00:58
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 07:55:53
* @Last Modified time: 2016-04-03 20:58:33
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
@ -111,4 +111,4 @@ function add() {
}
</script>
EOT;
View::show('footer', $data); ?>
View::show('admin/footer', $data); ?>

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-19 14:34:21
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 11:27:05
* @Last Modified time: 2016-04-03 20:58:26
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
@ -241,4 +241,4 @@ $('#color-submit').click(function() {
});
</script>
EOT;
View::show('footer', $data); ?>
View::show('admin/footer', $data); ?>

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-02-03 14:39:50
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 07:59:57
* @Last Modified time: 2016-04-03 20:58:22
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
@ -55,4 +55,4 @@ $db = new Database\Database('users');
</section><!-- /.content -->
</div><!-- /.content-wrapper -->
<?php
View::show('footer'); ?>
View::show('admin/footer'); ?>

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-06 14:19:20
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 07:55:53
* @Last Modified time: 2016-04-03 20:58:13
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
@ -26,4 +26,4 @@ $('#page-select').on('change', function() {
EOT;
if (isset($_GET['show']))
$data['script'] .= '<script type="text/javascript" src="../assets/js/preview.utils.js"></script>';
View::show('footer', $data); ?>
View::show('admin/footer', $data); ?>

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-18 22:50:25
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 15:09:33
* @Last Modified time: 2016-04-03 20:58:06
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
@ -200,4 +200,4 @@ $db = new Database\Database('users');
</section><!-- /.content -->
</div><!-- /.content-wrapper -->
<?php
View::show('footer'); ?>
View::show('admin/footer'); ?>

View File

@ -3,123 +3,27 @@
* @Author: printempw
* @Date: 2016-03-27 15:03:40
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 07:55:54
* @Last Modified time: 2016-04-03 21:05:51
*/
require "../libraries/session.inc.php";
if (!$user->is_admin) Utils::redirect('../index.php?msg=看起来你并不是管理员');
$action = isset($_GET['action']) ? $_GET['action'] : "";
$updater = new Updater(Option::get('current_version'));
if ($action == "check" && $updater->newVersionAvailable()) {
exit(json_encode([
'new_version_available' => true,
'latest_version' => $updater->latest_version
]));
}
View::show('admin/header', array('page_title' => "检查更新"));
$db = new Database\Database('users');
?>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
检查更新
<small>Check Updates</small>
</h1>
</section>
<?php
$updater = new Updater(Option::get('current_version'));
?>
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">更新信息</h3>
</div><!-- /.box-header -->
<div class="box-body">
<?php if ($updater->newVersionAvailable()): ?>
<div class="callout callout-info">有更新可用。</div>
<table class="table">
<tbody>
<tr>
<td class="key">最新版本:</td>
<td class="value">
v<?php echo $updater->latest_version; ?>
</td>
</tr>
<tr>
<td class="key">当前版本:</td>
<td class="value">
v<?php echo $updater->current_version; ?>
</td>
</tr>
<tr>
<td class="key">发布时间:</td>
<td class="value">
<?php echo $updater->update_time; ?>
</td>
</tr>
<tr>
<td class="key">更新日志:</td>
<td class="value">
<?php echo nl2br($updater->getUpdateInfo()['releases'][$updater->latest_version]['release_note']); ?>
</td>
</tr>
<tr>
<td class="key">下载地址:</td>
<td class="value">
<a href="<?php echo $updater->getUpdateInfo()['releases'][$updater->latest_version]['release_url']; ?>">@GitHub</a>
</td>
</tr>
</tbody>
</table>
<?php else: ?>
<div class="callout callout-success">已更新至最新版本。</div>
<table class="table">
<tbody>
<tr>
<td class="key">当前版本:</td>
<td class="value">
v<?php echo $updater->current_version; ?>
</td>
</tr>
<tr>
<td class="key">发布时间:</td>
<td class="value">
<?php echo date('Y-m-d H:i:s', $updater->getUpdateInfo()['releases'][$updater->current_version]['release_time']); ?>
</td>
</tr>
</tbody>
</table>
<?php endif; ?>
</div><!-- /.box-body -->
<div class="box-footer">
<a href="http://www.mcbbs.net/thread-552877-1-1.html" class="btn btn-primary">查看 MCBBS 发布贴</a>
</div>
</div>
</div>
if ($action == "download") {
View::show('admin/download');
} else {
View::show('admin/check');
}
<div class="col-md-6">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">更新流程</h3>
</div><!-- /.box-header -->
<div class="box-body">
<p>1. 下载新版源码</p>
<p>2. <strong>完全覆盖</strong>旧版目录</p>
<p>3. 运行 /setup/update-from-2.3.3-to-2.3.4.php</p>
<p>4. 升级完成</p>
</div><!-- /.box-body -->
</div>
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">关于</h3>
</div><!-- /.box-header -->
<div class="box-body">
<p>自动升级正在开发中,开发者现在忙于应考,可能要过几个星期才能发布。</p>
</div><!-- /.box-body -->
</div>
</div>
</div>
</section><!-- /.content -->
</div><!-- /.content-wrapper -->
<?php
View::show('footer'); ?>
View::show('admin/footer'); ?>

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-18 14:02:12
* @Last Modified by: printempw
* @Last Modified time: 2016-04-02 22:50:19
* @Last Modified time: 2016-04-03 21:47:08
*/
use Database\Database;
@ -27,6 +27,7 @@ class Option
public static function add($key, $value) {
$db = new Database('options');
if (self::has($key)) return true;
return $db->insert(['option_name' => $key, 'option_value' => $value]);
}

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-27 15:16:22
* @Last Modified by: printempw
* @Last Modified time: 2016-03-27 16:26:07
* @Last Modified time: 2016-04-03 21:15:23
*/
class Updater
@ -13,10 +13,13 @@ class Updater
public $update_time = "";
public $update_url = "https://work.prinzeugen.net/update.json";
public $update_url = "";
public $update_info = null;
function __construct($current_version) {
$this->current_version = $current_version;
$this->update_url = Option::get('update_url');
}
public function getUpdateInfo() {
@ -27,8 +30,8 @@ class Updater
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
$this->update_info = json_decode($result, true);
return $this->update_info;
}
public function checkUpdate() {
@ -37,6 +40,32 @@ class Updater
$this->update_time = date('Y-m-d H:i:s', $info['update_time']);
}
public function downloadUpdate($silent = true) {
$release_url = $this->update_info['releases'][$this->latest_version]['release_url'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $release_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
if (!$silent) echo "<p>正在下载更新包:$release_url </p>";
$file = curl_exec($ch);
if (!$silent) echo "<p>下载完成。</p>";
curl_close($ch);
$update_cache = BASE_DIR."/setup/update_cache/";
if (!is_dir($update_cache)) mkdir($update_cache);
$zip_path = $update_cache."update_".time().".zip";
if (file_put_contents($zip_path, $file) === false) {
Utils::removeDir(BASE_DIR.'/setup/update_cache/');
return false;
}
return $zip_path;
}
/**
* Check if a new version is available
*

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-01-16 23:01:33
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 10:58:15
* @Last Modified time: 2016-04-03 21:44:11
*/
class Utils
@ -38,13 +38,28 @@ class Utils
* @return $bool
*/
public static function remove($filename) {
if(file_exists($filename)) {
if (!unlink($filename)) {
self::raise(-1, "删除 $filename 的时候出现了奇怪的问题。。请联系作者");
} else {
return true;
if (file_exists($filename)) {
return unlink($filename);
}
}
public static function removeDir($dir) {
$resource = opendir($dir);
$size = 0;
while($filename = @readdir($resource)) {
if ($filename != "." && $filename != "..") {
$path = $dir.$filename;
if (is_dir($path)) {
// recursion
self::removeDir($path."/");
} else {
unlink($path);
}
}
}
closedir($resource);
return rmdir($dir);
}
/**
@ -56,7 +71,7 @@ class Utils
public static function getDirSize($dir) {
$resource = opendir($dir);
$size = 0;
while($filename = readdir($resource)) {
while($filename = @readdir($resource)) {
if ($filename != "." && $filename != "..") {
$path = $dir.$filename;
if (is_dir($path)) {
@ -95,6 +110,33 @@ class Utils
return $file_num;
}
/**
* Copy directory recursively
*
* @param string $source
* @param string $dest
* @return bool
*/
public static function copyDir($source, $dest) {
if(!is_dir($source)) return false;
if(!is_dir($dest)) mkdir($dest, 0777, true);
$handle = dir($source);
while($entry = $handle->read()) {
if ($entry != "." && $entry != "..") {
if (is_dir($source.'/'.$entry)) {
// recursion
self::copyDir($source.'/'.$entry, $dest.'/'.$entry);
} else {
@copy($source.'/'.$entry, $dest.'/'.$entry);
// echo $source.'/'.$entry." => ".$dest.'/'.$entry."<br />";
}
}
}
return true;
}
/**
* Simple SQL injection protection
*
@ -184,8 +226,11 @@ class Utils
* @param string $url
* @return null
*/
public static function redirect($url) {
header('Location: '.$url);
public static function redirect($url, $use_js = false) {
if ($use_js)
echo "<script>window.location = '$url';</script>";
else
header('Location: '.$url);
}
}

View File

@ -3,7 +3,7 @@
* @Author: printempw
* @Date: 2016-03-27 13:30:00
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 16:16:57
* @Last Modified time: 2016-04-03 19:23:11
*/
// Sanity check
@ -44,9 +44,7 @@ $step = isset($_GET['step']) ? $_GET['step'] : 1;
<?php
// use error control to hide shitty connect warnings
error_reporting(0);
$conn = new mysqli(DB_HOST, DB_USER, DB_PASSWD, DB_NAME, DB_PORT);
error_reporting(E_ALL ^ E_NOTICE);
@$conn = new mysqli(DB_HOST, DB_USER, DB_PASSWD, DB_NAME, DB_PORT);
if ($conn->connect_error): ?>
<h1>MySQL 连接错误</h1>

View File

@ -2,7 +2,7 @@
* @Author: printempw
* @Date: 2016-04-03 16:22:11
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 17:14:53
* @Last Modified time: 2016-04-03 21:22:18
*/
CREATE TABLE IF NOT EXISTS `{$prefix}users` (
@ -33,7 +33,7 @@ INSERT INTO `{$prefix}options` (`option_name`, `option_value`) VALUES
('user_can_register', '1'),
('user_default_skin', ''),
('regs_per_ip', '2'),
('upload_max_size', '10'),
('upload_max_size', '1024'),
('api_type', '0'),
('announcement', '这是默认的公告~'),
('data_adapter', ''),
@ -44,7 +44,8 @@ INSERT INTO `{$prefix}options` (`option_name`, `option_value`) VALUES
('data_column_ip', 'ip'),
('color_scheme', 'skin-blue'),
('home_pic_url', './assets/images/bg.jpg'),
('google_font_cdn', ''),
('google_font_cdn', 'moefont'),
('custom_css', ''),
('custom_js', '');
('custom_js', ''),
('update_url', 'https://work.prinzeugen.net/update.json');

74
setup/update.php Normal file
View File

@ -0,0 +1,74 @@
<?php
/**
* @Author: printempw
* @Date: 2016-04-03 19:20:47
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 20:48:15
*/
session_start();
$dir = dirname(dirname(__FILE__));
require "$dir/libraries/autoloader.php";
$step = isset($_GET['step']) ? $_GET['step'] : 1;
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex,nofollow" />
<title>Blessing Skin Server 升级程序</title>
<link rel="stylesheet" type="text/css" href="../assets/css/install.style.css">
</head>
<body class="container">
<p id="logo"><a href="https://github.com/printempw/blessing-skin-server" tabindex="-1">Blessing Skin Server</a></p>
<?php
$updater = new Updater(Option::get('current_version'));
if (!$updater->newVersionAvailable()): ?>
<h1>并没有可用的更新</h1>
<p>当前版本v<?php echo $updater->current_version; ?></p>
<p class="step"><a href="../index.php" class="button button-large">返回首页</a></p>
<?php exit; endif;
if (!isset($_SESSION['downloaded_version'])): ?>
<h1>非法访问</h1>
<p>下载完更新后再来吧</p>
<p class="step"><a href="../admin/update.php" class="button button-large">检查更新</a></p>
<?php exit; endif;
/*
* Stepped installation
*/
switch ($step) {
// Step 1
case 1: ?>
<h1>还差一小步</h1>
<p>我们需要先升级下数据库。点击下一步以继续。</p>
<p class="step"><a href="?step=2" class="button button-large">下一步</a></p>
<?php break;
// Step 2
case 2: ?>
<h1>升级数据库</h1>
<?php
$resource = opendir(dirname(__FILE__)."/update_scripts/");
while($filename = @readdir($resource)) {
if ($filename != "." && $filename != "..") {
preg_match('/update-(.*)-to-(.*).php/', $filename, $matches);
if (!isset($matches[2])) continue;
include dirname(__FILE__)."/update_scripts/".$filename;
}
}
closedir($resource);
echo "<p>数据库升级成功。欢迎使用 Blessing Skin Server v{$updater->current_version}</p>"
?>
<p class="step"><a href="../index.php" class="button button-large">进入首页</a></p>
<?php break; ?>
</body>
</html>
<?php }

View File

@ -3,13 +3,12 @@
* @Author: printempw
* @Date: 2016-03-27 15:56:29
* @Last Modified by: printempw
* @Last Modified time: 2016-03-27 16:30:44
* @Last Modified time: 2016-04-03 21:23:20
*/
require "../libraries/session.inc.php";
if (!defined('BASE_DIR')) exit('请运行 /setup/update.php 来升级');
if (!Option::has('current_version') || Option::get('current_version') == "2.3.3") {
Option::set('current_version', '2.3.4');
echo "升级成功。";
} else {
echo "已升级至 v2.3.4,请不要重复运行。";
echo "已成功升级至 v2.3.4";
}

View File

@ -0,0 +1,22 @@
<?php
/**
* @Author: printempw
* @Date: 2016-04-03 19:48:02
* @Last Modified by: printempw
* @Last Modified time: 2016-04-03 21:23:17
*/
if (!defined('BASE_DIR')) exit('请运行 /setup/update.php 来升级');
if (Option::get('current_version') == "2.3.4") {
Option::add('upload_max_size', '1024');
Option::add('custom_css', '');
Option::add('custom_js', '');
Option::add('google_font_cdn', 'moefont');
Option::add('user_default_skin', '');
Option::add('encryption', 'MD5');
Option::add('update_url', 'https://work.prinzeugen.net/update.json');
Option::set('current_version', '2.4');
echo "已成功升级至 v2.4";
}

View File

@ -0,0 +1,87 @@
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
检查更新
<small>Check Updates</small>
</h1>
</section>
<?php $updater = new Updater(Option::get('current_version')); ?>
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">更新信息</h3>
</div><!-- /.box-header -->
<div class="box-body">
<?php if ($updater->newVersionAvailable()): ?>
<div class="callout callout-info">有更新可用。</div>
<table class="table">
<tbody>
<tr>
<td class="key">最新版本:</td>
<td class="value">
v<?php echo $updater->latest_version; ?>
</td>
</tr>
<tr>
<td class="key">当前版本:</td>
<td class="value">
v<?php echo $updater->current_version; ?>
</td>
</tr>
<tr>
<td class="key">发布时间:</td>
<td class="value">
<?php echo $updater->update_time; ?>
</td>
</tr>
<tr>
<td class="key">更新日志:</td>
<td class="value">
<?php echo nl2br($updater->getUpdateInfo()['releases'][$updater->latest_version]['release_note']); ?>
</td>
</tr>
<tr>
<td class="key">下载地址:</td>
<td class="value">
<a href="<?php echo $updater->getUpdateInfo()['releases'][$updater->latest_version]['release_url']; ?>">@GitHub</a>
</td>
</tr>
</tbody>
</table>
<?php else: ?>
<div class="callout callout-success">已更新至最新版本。</div>
<table class="table">
<tbody>
<tr>
<td class="key">当前版本:</td>
<td class="value">
v<?php echo $updater->current_version; ?>
</td>
</tr>
<tr>
<td class="key">发布时间:</td>
<td class="value">
<?php echo date('Y-m-d H:i:s', $updater->getUpdateInfo()['releases'][$updater->current_version]['release_time']); ?>
</td>
</tr>
</tbody>
</table>
<?php endif; ?>
</div><!-- /.box-body -->
<div class="box-footer">
<a <?php if (!$updater->newVersionAvailable()) echo "disabled='disabled'"; ?> href="update.php?action=download" class="btn btn-primary">马上升级</a>
<a href="http://www.mcbbs.net/thread-552877-1-1.html" style="float: right;" class="btn btn-default">查看 MCBBS 发布贴</a>
</div>
</div>
</div>
</div>
</section><!-- /.content -->
</div><!-- /.content-wrapper -->

View File

@ -0,0 +1,60 @@
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
下载更新
<small>Download Updates</small>
</h1>
</section>
<!-- Main content -->
<section class="content">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title">下载更新</h3>
</div><!-- /.box-header -->
<div class="box-body"> <?php
$updater = new Updater(Option::get('current_version'));
if ($updater->newVersionAvailable()) {
$zip_path = $updater->downloadUpdate(false);
if ($zip_path === false) {
exit('<p>无法下载更新包。</p>');
}
$zip = new ZipArchive();
$extract_dir = BASE_DIR."/setup/update_cache/{$updater->latest_version}";
if ($zip->open($zip_path) === true) {
echo "<p>正在解压更新包</p>";
$zip->extractTo($extract_dir);
} else {
exit('<p>更新包解压缩失败。</p>');
}
$zip->close();
if (Utils::copyDir($extract_dir, BASE_DIR) !== true) {
Utils::removeDir(BASE_DIR.'/setup/update_cache/');
exit('无法覆盖文件。');
} else {
echo "<p>正在覆盖文件</p>";
Utils::removeDir(BASE_DIR.'/setup/update_cache/');
echo "<p>正在清理</p>";
}
echo "<p>更新完成。</p>";
$_SESSION['downloaded_version'] = $updater->latest_version;
} else {
Utils::redirect('update.php', true);
} ?>
</div><!-- /.box-body -->
<div class="box-footer">
<a href="../setup/update.php" class="btn btn-primary">下一步</a>
</div>
</div>
</section><!-- /.content -->
</div><!-- /.content-wrapper -->

View File

@ -0,0 +1,16 @@
<?php
$data['script'] = isset($data['script']) ? $data['script'] : "";
$data['script'] .= <<< 'EOT'
<script>
$(document).ready(function() {
$.getJSON('update.php?action=check', function(data) {
if (data.new_version_available == true)
$('[href="update.php"]').append('<span class="label label-primary pull-right">v'+data.latest_version+'</span>');
})
});
</script>
EOT;
View::show('footer', $data);