move setup wizard into laravel framework

This commit is contained in:
printempw 2016-11-18 16:46:58 +08:00
parent fbea8e0905
commit 589be0c892
35 changed files with 297 additions and 829 deletions

View File

@ -10,6 +10,7 @@ use Illuminate\Foundation\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
class Handler extends ExceptionHandler
{
@ -22,7 +23,8 @@ class Handler extends ExceptionHandler
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
PrettyPageException::class
PrettyPageException::class,
MethodNotAllowedHttpException::class,
];
/**
@ -47,23 +49,30 @@ class Handler extends ExceptionHandler
*/
public function render($request, Exception $e)
{
if ($e instanceof HttpException) {
// call i18n middleware manually since http exceptions won't be sent through it
(new Internationalization)->handle($request, function(){});
}
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
}
if ($e instanceof MethodNotAllowedHttpException) {
abort(403, 'Method not allowed.');
}
if ($e instanceof PrettyPageException && PHP_SAPI != "cli") {
return $e->showErrorPage();
}
if ($e instanceof HttpException) {
// call i18n middleware manually since http exceptions won't be sent through it
(new Internationalization)->handle($request, function(){});
}
if ($e instanceof ValidationException) {
// quick fix for returning 422
// @see https://prinzeugen.net/custom-responses-of-laravel-validations/
return $e->getResponse()->setStatusCode(200);
}
// render exceptions with whoops
if (config('app.debug')) {
foreach ($this->dontReport as $type) {
if ($e instanceof $type) {

View File

@ -0,0 +1,152 @@
<?php
namespace App\Http\Controllers;
use Utils;
use Schema;
use Option;
use Artisan;
use Database;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Validation\Validator;
class SetupController extends Controller
{
public function welcome()
{
// already installed
if ($this->checkTablesExist()) {
return view('setup.locked');
} else {
$config = config('database.connections.mysql');
return view('setup.wizard.welcome')->with('server', "{$config['username']}@{$config['host']}");
}
}
public function update()
{
if (version_compare(config('app.version'), option('version', ''), '<=')) {
// no updates available
return view('setup.locked');
}
return view('setup.updates.welcome');
}
public function doUpdate()
{
$resource = opendir(database_path('update_scripts'));
$update_script_exist = false;
$tips = [];
while($filename = @readdir($resource)) {
if ($filename != "." && $filename != "..") {
preg_match('/update-(.*)-to-(.*).php/', $filename, $matches);
// skip if the file is not valid or expired
if (!isset($matches[2]) ||
version_compare($matches[2], option('version'), '<')) {
continue;
}
$result = require database_path('update_scripts')."/$filename";
if (is_array($result)) {
// push tip to array
foreach ($result as $tip) {
$tips[] = $tip;
}
}
$update_script_exist = true;
}
}
closedir($resource);
foreach (config('options') as $key => $value) {
if (!Option::has($key))
Option::set($key, $value);
}
if (!$update_script_exist) {
// if update script is not given
Option::set('version', config('app.version'));
}
return view('setup.updates.success', ['tips' => $tips]);
}
public function info()
{
return view('setup.wizard.info');
}
public function finish(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:6|max:16|confirmed',
'site_name' => 'required'
]);
// create tables
Artisan::call('migrate');
Option::set('site_name', $request->input('site_name'));
Option::set('site_url', url('/'));
// register super admin
$user = User::register(
$request->input('email'),
$request->input('password'),
function ($user)
{
$user->ip = get_real_ip();
$user->score = option('user_initial_score');
$user->register_at = Utils::getTimeFormatted();
$user->last_sign_at = Utils::getTimeFormatted(time() - 86400);
$user->permission = User::SUPER_ADMIN;
});
$this->createDirectories();
return view('setup.wizard.finish')->with([
'email' => $request->input('email'),
'password' => $request->input('password')
]);
}
protected function createDirectories()
{
if (!is_dir(BASE_DIR.'/storage/textures/')) {
if (!mkdir(BASE_DIR.'/storage/textures/'))
throw new App\Exceptions\PrettyPageException('/storage/textures 文件夹创建失败,请检查目录权限是否正确,或者手动放置一个。', -1);
}
}
protected function checkTablesExist()
{
$tables = ['users', 'closets', 'players', 'textures', 'options'];
foreach ($tables as $table_name) {
// prefix will be added automatically
if (!Schema::hasTable($table_name)) {
return false;
}
}
return true;
}
/**
* {@inheritdoc}
*/
protected function formatValidationErrors(Validator $validator)
{
return $validator->errors()->all();
}
}

View File

@ -16,12 +16,25 @@ Route::get('/index.php', 'HomeController@index');
Route::get('/locale/{lang}', 'HomeController@locale');
/**
* Setup Wizard
*/
Route::group(['prefix' => 'setup'], function ()
{
Route::get ('/', 'SetupController@welcome');
Route::get ('/info', 'SetupController@info');
Route::post('/finish', 'SetupController@finish');
Route::get ('/update', 'SetupController@update');
Route::post('/update', 'SetupController@doUpdate');
});
/**
* Auth
*/
Route::group(['prefix' => 'auth'], function()
Route::group(['prefix' => 'auth'], function ()
{
Route::group(['middleware' => 'guest'], function()
Route::group(['middleware' => 'guest'], function ()
{
Route::get ('/login', 'AuthController@login');
Route::get ('/register', 'AuthController@register');
@ -42,7 +55,7 @@ Route::group(['prefix' => 'auth'], function()
/**
* User Center
*/
Route::group(['middleware' => 'auth', 'prefix' => 'user'], function()
Route::group(['middleware' => 'auth', 'prefix' => 'user'], function ()
{
Route::any ('', 'UserController@index');
Route::any ('/checkin', 'UserController@checkIn');
@ -73,14 +86,14 @@ Route::group(['middleware' => 'auth', 'prefix' => 'user'], function()
/**
* Skin Library
*/
Route::group(['prefix' => 'skinlib'], function()
Route::group(['prefix' => 'skinlib'], function ()
{
Route::get ('', 'SkinlibController@index');
Route::any ('/info/{tid}', 'SkinlibController@info');
Route::any ('/show', 'SkinlibController@show');
Route::any ('/search', 'SkinlibController@search');
Route::group(['middleware' => 'auth'], function()
Route::group(['middleware' => 'auth'], function ()
{
Route::get ('/upload', 'SkinlibController@upload');
Route::post('/upload', 'SkinlibController@handleUpload');
@ -94,7 +107,7 @@ Route::group(['prefix' => 'skinlib'], function()
/**
* Admin Panel
*/
Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function()
Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function ()
{
Route::get('/', 'AdminController@index');

View File

@ -33,11 +33,8 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->singleton('database', \App\Services\Database\Database::class);
$this->app->singleton('option', \App\Services\Repositories\OptionRepository::class);
// register default cipher
$this->app->singleton('cipher', "App\Services\Cipher\\".config('secure.cipher'));
$this->app->singleton('users', \App\Services\Repositories\UserRepository::class);
}
}

View File

@ -3,6 +3,8 @@
namespace App\Providers;
use View;
use Schema;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use App\Exceptions\PrettyPageException;
@ -13,64 +15,73 @@ class BootServiceProvider extends ServiceProvider
*
* @return void
*/
public function boot()
public function boot(Request $request)
{
View::addExtension('tpl', 'blade');
$this->checkFileExists();
$this->checkDbConfig();
$this->checkInstallation();
if (!$request->is('setup') && !$request->is('setup/*') && PHP_SAPI != "cli") {
$this->checkInstallation();
}
}
protected function checkFileExists()
{
if (!file_exists(BASE_DIR."/.env")) {
throw new PrettyPageException('.env 文件不存在', -1);
throw new PrettyPageException(trans('setup.file.no-dot-env'), -1);
}
}
protected function checkDbConfig()
{
$config = config('database.connections.mysql');
// use error control to hide shitty connect warnings
@$conn = new \mysqli(
config('database.connections.mysql.host'),
config('database.connections.mysql.username'),
config('database.connections.mysql.password'),
config('database.connections.mysql.database'),
config('database.connections.mysql.port')
$config['host'],
$config['username'],
$config['password'],
$config['database'],
$config['port']
);
if ($conn->connect_error)
throw new PrettyPageException("无法连接至 MySQL 服务器,请检查你的配置:".$conn->connect_error, $conn->connect_errno);
throw new PrettyPageException(
trans('setup.database.connection-error', ['msg' => $conn->connect_error]),
$conn->connect_errno
);
return true;
}
protected function checkInstallation()
{
if (!$this->checkTableExist()) {
return redirect('/setup/index.php')->send();
// redirect to setup wizard
if (!$this->checkTablesExist()) {
return redirect('/setup')->send();
}
if (!is_dir(BASE_DIR.'/storage/textures/')) {
if (!mkdir(BASE_DIR.'/storage/textures/'))
throw new PrettyPageException('textures 文件夹创建失败,请确认目录权限是否正确,或者手动放置一个。', -1);
throw new PrettyPageException(trans('setup.file.permission-error'), -1);
}
if (config('app.version') != \Option::get('version', '')) {
return redirect('/setup/update.php')->send();
if (version_compare(config('app.version'), option('version', ''), '>')) {
return redirect('/setup/update')->send();
}
return true;
}
public static function checkTableExist()
public static function checkTablesExist()
{
$tables = ['users', 'closets', 'players', 'textures', 'options'];
foreach ($tables as $table_name) {
// prefix will be added automatically
if (!\Schema::hasTable($table_name)) {
if (!Schema::hasTable($table_name)) {
return false;
}
}
@ -85,6 +96,7 @@ class BootServiceProvider extends ServiceProvider
*/
public function register()
{
//
$this->app->singleton('database', \App\Services\Database\Database::class);
$this->app->singleton('options', \App\Services\Repositories\OptionRepository::class);
}
}

View File

@ -49,7 +49,7 @@ class Database
);
if ($this->connection->connect_error)
throw new \InvalidArgumentException("Could not connect to MySQL database. Check your configuration:".
throw new \InvalidArgumentException("Could not connect to MySQL database. ".
$this->connection->connect_error, $this->connection->connect_errno);
$this->connection->query("SET names 'utf8'");

View File

@ -14,7 +14,7 @@ class Option extends Facade
*/
protected static function getFacadeAccessor()
{
return 'option';
return 'options';
}
public static function form($id, $title, $callback)

View File

@ -8,13 +8,6 @@ use Illuminate\Database\QueryException;
class OptionRepository extends Repository
{
/**
* All of the option items that is modified.
*
* @var array
*/
protected $items_modified = [];
/**
* Create a new option repository.
*
@ -76,7 +69,7 @@ class OptionRepository extends Repository
*
* @return void
*/
protected function save()
public function save()
{
$this->items_modified = array_unique($this->items_modified);

View File

@ -14,6 +14,13 @@ class Repository implements ArrayAccess // Illuminate\Contracts\Cache\Repository
*/
protected $items;
/**
* All of the option items that is modified.
*
* @var array
*/
protected $items_modified = [];
/**
* Determine if an item exists in the repository.
*

View File

@ -179,9 +179,22 @@ if (! function_exists('bs_nickname')) {
if (! function_exists('option')) {
function option($key)
function option($key = null, $default = null)
{
return Option::get($key);
$options = app('options');
if (is_null($key)) {
return $options;
}
if (is_array($key)) {
foreach ($key as $innerKey => $innerValue) {
$options->set($innerKey, $innerValue);
}
return $options->save();
}
return $options->get($key);
}
}

View File

@ -18,7 +18,8 @@
},
"autoload": {
"classmap": [
"app/Models"
"app/Models",
"database"
],
"psr-4": {
"App\\": "app/"

View File

@ -0,0 +1,13 @@
<?php
/**
* @Author: printempw
* @Date: 2016-11-18 16:25:35
* @Last Modified by: printempw
* @Last Modified time: 2016-11-18 16:33:32
*/
Option::set('version', '3.2');
return [
'v3.2 新加入了插件系统,支持的插件请去程序发布帖查看'
];

View File

@ -2,7 +2,7 @@
* @Author: printempw
* @Date: 2016-07-28 13:15:18
* @Last Modified by: printempw
* @Last Modified time: 2016-08-10 17:50:19
* @Last Modified time: 2016-11-18 15:12:18
*/
@import "style.scss";
@ -94,6 +94,10 @@ p {
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
ul {
margin: 0px;
}
}
.alert-warning {

View File

@ -91,6 +91,7 @@ custom:
attributes:
file: File
name: Name
player_name: 'Player Name'
new_player_name: 'Player Name'
player_name: Player Name
new_player_name: Player Name
identification: Email or player name
site name: Site Name

View File

@ -0,0 +1,6 @@
database:
connection-error: 无法连接至 MySQL 服务器,请检查你的配置 :msg
file:
permission-error: textures 文件夹创建失败,请确认目录权限是否正确,或者手动放置一个。
no-dot-env: 找不到 .env 配置文件

View File

@ -84,6 +84,7 @@ attributes:
username: 用户名
identification: 邮箱或角色名
new_player_name: 角色名
sitename: 站点名称
nickname: 昵称
player_name: 角色名
email: 邮箱

View File

@ -1,10 +1,10 @@
@extends('setup.master')
@extends('setup.wizard.master')
@section('content')
<h1>已安装过</h1>
<p>Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除数据库中的旧数据表,或者换一个数据表前缀。</p>
<p class="step">
<a href="../" class="button button-large">返回首页</a>
<a href="{{ url('/') }}" class="button button-large">返回首页</a>
</p>
@endsection

View File

@ -16,6 +16,6 @@
@endif
<p class="step">
<a href="../" class="button button-large">首页</a>
<a href="{{ url('/') }}" class="button button-large">首页</a>
</p>
@endsection

View File

@ -6,7 +6,9 @@
<p>欢迎升级至 Blessing Skin Server {{ config('app.version') }}</p>
<p>我们需要升级您的数据库,点击下一步以继续。</p>
<p class="step">
<a href="update.php?step=2" class="button button-large">下一步</a>
</p>
<form method="post" action="" novalidate="novalidate">
<p class="step">
<input type="submit" name="submit" class="button button-large" value="下一步" />
</p>
</form>
@endsection

View File

@ -1,4 +1,4 @@
@extends('setup.master')
@extends('setup.wizard.master')
@section('content')
<h1>成功!</h1>

View File

@ -1,10 +1,10 @@
@extends('setup.master')
@extends('setup.wizard.master')
@section('content')
<h1>填写信息</h1>
<p>您需要填写一些基本信息。无需担心填错,这些信息以后可以再次修改。</p>
<form id="setup" method="post" action="index.php?step=3" novalidate="novalidate">
<form id="setup" method="post" action="{{ url('setup/finish') }}" novalidate="novalidate">
<table class="form-table">
<tr>
<th scope="row"><label for="email">管理员邮箱</label></th>
@ -25,30 +25,36 @@
</td>
</tr>
<tr class="form-field form-required">
<th scope="row"><label for="confirm-pwd">重复密码</label></th>
<th scope="row"><label for="password_confirmation">重复密码</label></th>
<td>
<input type="password" name="confirm-pwd" id="confirm-pwd" autocomplete="off" />
<input type="password" name="password_confirmation" id="password_confirmation" autocomplete="off" />
</td>
</tr>
<tr>
<th scope="row"><label for="sitename">站点名称</label></th>
<th scope="row"><label for="site_name">站点名称</label></th>
<td>
<input name="sitename" type="text" id="sitename" size="25" value="" />
<input name="site_name" type="text" id="site_name" size="25" value="Blessing Skin Server" />
<p>
<span class="description important">
将会显示在首页以及标题栏,最好用纯英文(字体原因)
将会显示在首页以及标题栏
</span>
</p>
</td>
</tr>
</table>
@if (isset($_SESSION['msg']))
<div class="alert alert-warning" role="alert">{{ $_SESSION['msg'] }}</div> <?php unset($_SESSION['msg']); ?>
@if (count($errors) > 0)
<div class="alert alert-warning" role="alert">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<p class="step">
<input type="submit" name="Submit" id="submit" class="button button-large" value="开始安装" />
<input type="submit" name="submit" id="submit" class="button button-large" value="开始安装" />
</p>
</form>
@endsection

View File

@ -1,4 +1,4 @@
@extends('setup.master')
@extends('setup.wizard.master')
@section('content')
<h1>欢迎</h1>
@ -7,6 +7,6 @@
<p>成功连接至 MySQL 服务器 {{ $server }},点击下一步以开始安装。</p>
<p class="step">
<a href="?step=2" class="button button-large">下一步</a>
<a href="{{ url('setup/info') }}" class="button button-large">下一步</a>
</p>
@endsection

View File

@ -1,113 +0,0 @@
<?php
/**
* Setup Bootstraper of Blessing Skin Server
*/
// Define Base Directory
define('BASE_DIR', dirname(dirname(__DIR__)));
// Set Display Errors
@ini_set('display_errors', 'on');
// Register Composer Auto Loader
if (file_exists(BASE_DIR.'/vendor')) {
require BASE_DIR.'/vendor/autoload.php';
} else {
exit('错误:/vendor 文件夹不存在');
}
// Register Helpers
require BASE_DIR.'/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php';
require __DIR__."/helpers.php";
// Load dotenv Configuration
if (file_exists(BASE_DIR."/.env")) {
$dotenv = new \Dotenv\Dotenv(BASE_DIR);
$dotenv->load();
} else {
exit('错误:.env 配置文件不存在');
}
if (false === menv('APP_KEY', false)) {
exit('错误:.env 已过期,请重新复制一份 .env.example 并修改配置');
}
// Register Error Hanlders
$whoops = new \Whoops\Run;
$handler = new \Whoops\Handler\PrettyPageHandler;
$whoops->pushHandler($handler);
$whoops->register();
// Instantiate Application
$app = new Illuminate\Foundation\Application(BASE_DIR);
// Set Container for Facades
Illuminate\Support\Facades\Facade::setFacadeApplication($app);
// Load Aliases
$config = require BASE_DIR.'/config/app.php';
foreach ($config['aliases'] as $facade => $class) {
class_alias($class, $facade);
}
// Register Basic Service Providers manually
(new Illuminate\View\ViewServiceProvider($app))->register();
(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
(new Illuminate\Database\DatabaseServiceProvider($app))->register();
(new Illuminate\Filesystem\FilesystemServiceProvider($app))->register();
(new Illuminate\Session\SessionServiceProvider($app))->register();
(new Illuminate\Encryption\EncryptionServiceProvider($app))->register();
(new Devitek\Core\Translation\TranslationServiceProvider($app))->register();
$request = Symfony\Component\HttpFoundation\Request::createFromGlobals();
$request = (new Illuminate\Http\Request)->duplicate(
$request->query->all(), $request->request->all(), $request->attributes->all(),
// quick fix: replace request URI with empty string
$request->cookies->all(), $request->files->all(), array_replace($request->server->all(), ['REQUEST_URI' => ''])
);
// Enable URL generator
$app->bind('url', function ($app) {
$routes = $app['router']->getRoutes();
$app->instance('routes', $routes);
$url = new Illuminate\Routing\UrlGenerator(
$routes, $app['request']
);
return $url;
});
$app->instance('request', $request);
$app->singleton('database', App\Services\Database\Database::class);
$app->singleton('option', App\Services\Repositories\OptionRepository::class);
$app->singleton('cipher', "App\Services\Cipher\\".config('secure.cipher'));
$app->singleton('users', App\Services\Repositories\UserRepository::class);
View::addExtension('tpl', 'blade');
$db_config = get_db_config();
// Check Database Config
check_db_config($db_config);
// Boot Eloquent ORM
$capsule = new Illuminate\Database\Capsule\Manager;
$capsule->addConnection($db_config);
$capsule->setAsGlobal();
$capsule->bootEloquent();
// Start Session
session_start();
// start laravel session
$encrypter = $app->make('Illuminate\Contracts\Encryption\Encrypter');
$session = $app->make('session')->driver();
if (isset($_COOKIE['BS_SESSION'])) {
$session->setId($encrypter->decrypt($_COOKIE['BS_SESSION']));
}
$session->start();

View File

@ -1,88 +0,0 @@
<?php
/**
* @Author: printempw
* @Date: 2016-09-14 16:57:37
* @Last Modified by: printempw
* @Last Modified time: 2016-10-23 13:23:24
*/
function check_table_exists() {
$tables = ['users', 'closets', 'players', 'textures', 'options'];
foreach ($tables as $table_name) {
// prefix will be added automatically
if (!Database::hasTable(config('database.connections.mysql.prefix').$table_name)) {
return false;
}
}
return true;
}
function redirect_to($url, $msg = "") {
// if ($msg !== "") {
// if (app()->bound('session')) {
// Session::put('msg', $msg);
// Session::save();
// } else {
$_SESSION['msg'] = $msg;
// }
// }
if (!headers_sent()) {
header('Location: '.$url);
} else {
echo "<meta http-equiv='Refresh' content='0; URL=$url'>";
}
exit;
}
/**
* Check POST values in a simple way
*
* @param array $keys
* @return void
*/
function check_post(Array $keys) {
foreach ($keys as $key) {
if (!isset($_POST[$key])) {
return false;
}
}
return true;
}
function check_password($password)
{
if (strlen($password) > 16 || strlen($password) < 8) {
return false;
}
return true;
}
function get_db_config()
{
$config = require BASE_DIR.'/config/database.php';
return $config['connections']['mysql'];
}
function check_db_config($config)
{
@$conn = new mysqli($config['host'], $config['username'], $config['password'], $config['database'], $config['port']);
if ($conn->connect_error) {
throw new App\Exceptions\PrettyPageException("无法连接至 MySQL 服务器,请检查你的配置:".$conn->connect_error, $conn->connect_errno, true);
}
}
function migrate($migration)
{
if (strpos($migration, 'import') !== false) {
$filename = BASE_DIR."/setup/migrations/".str_replace('-', '_', $migration).".php";
if (file_exists($filename)) {
return require $filename;
}
}
throw new InvalidArgumentException('Non-existent migration');
}

View File

@ -1,54 +0,0 @@
<?php
/**
* @Author: printempw
* @Date: 2016-08-06 19:39:12
* @Last Modified by: printempw
* @Last Modified time: 2016-08-15 12:24:34
*/
Schema::create('users', function($table) {
$table->increments('uid');
$table->string('email', 100);
$table->string('nickname', 50)->default('');
$table->integer('score');
$table->integer('avatar')->default('0');
$table->string('password', 255);
$table->string('ip', 32);
$table->integer('permission')->default('0');
$table->dateTime('last_sign_at');
$table->dateTime('register_at');
});
Schema::create('closets', function($table) {
$table->increments('uid');
$table->longText('textures');
});
Schema::create('players', function($table) {
$table->increments('pid');
$table->integer('uid');
$table->string('player_name', 50);
$table->string('preference', 10);
$table->integer('tid_steve')->default('0');
$table->integer('tid_alex')->default('0');
$table->integer('tid_cape')->default('0');
$table->dateTime('last_modified');
});
Schema::create('textures', function($table) {
$table->increments('tid');
$table->string('name', 50);
$table->string('type', 10);
$table->integer('likes');
$table->string('hash', 64);
$table->integer('size');
$table->integer('uploader');
$table->integer('public');
$table->dateTime('upload_at');
});
Schema::create('options', function($table) {
$table->increments('id');
$table->string('option_name', 50);
$table->longText('option_value');
});

View File

@ -1,90 +0,0 @@
<?php
/**
* Installation of Blessing Skin Server
*/
require __DIR__."/includes/bootstrap.php";
// If already installed
if (check_table_exists()) {
View::show('setup.locked');
exit;
}
$step = isset($_GET['step']) ? $_GET['step'] : 1;
/*
* Stepped installation
*/
switch ($step) {
case 1:
$server = $db_config['username']."@".$db_config['host'];
echo View::make('setup.steps.1')->with('server', $server);
break;
case 2:
echo View::make('setup.steps.2');
break;
case 3:
// check post
if (check_post(['email', 'password', 'confirm-pwd'], true))
{
if ($_POST['password'] != $_POST['confirm-pwd'])
redirect_to('index.php?step=2', '确认密码不一致');
$email = $_POST['email'];
$password = $_POST['password'];
$sitename = isset($_POST['sitename']) ? $_POST['sitename'] : "Blessing Skin Server";
if (validate($email, 'email')) {
if (!check_password($password)) {
redirect_to('index.php?step=2', '无效的密码。密码长度应该大于 8 并小于 16。');
} else if (e($password) != $password) {
redirect_to('index.php?step=2', '无效的密码。密码中包含了奇怪的字符。');
}
} else {
redirect_to('index.php?step=2', '邮箱格式不正确。');
}
}
else {
redirect_to('index.php?step=2', '表单信息不完整。');
}
// create tables
require BASE_DIR."/setup/includes/tables.php";
// import options
$options = require BASE_DIR."/config/options.php";
$options['site_name'] = $_POST['sitename'];
$options['site_url'] = url('/');
$options['version'] = config('app.version');
$options['announcement'] = str_replace('{version}', $options['version'], $options['announcement']);
foreach ($options as $key => $value) {
Option::set($key, $value);
}
// register super admin
$user = App\Models\User::register($_POST['email'], $_POST['password'], function($user) {
$user->ip = get_real_ip();
$user->score = option('user_initial_score');
$user->register_at = Utils::getTimeFormatted();
$user->last_sign_at = Utils::getTimeFormatted(time() - 86400);
$user->permission = App\Models\User::SUPER_ADMIN;
});
if (!is_dir(BASE_DIR.'/storage/textures/')) {
if (!mkdir(BASE_DIR.'/storage/textures/'))
throw new App\Exceptions\PrettyPageException('/storage/textures 文件夹创建失败,请检查目录权限是否正确,或者手动放置一个。', -1);
}
echo View::make('setup.steps.3')->with('email', $_POST['email'])->with('password', $_POST['password']);
break;
default:
throw new App\Exceptions\PrettyPageException('非法参数', 1, true);
break;
}

View File

@ -1,143 +0,0 @@
<?php
/**
* @Author: printempw
* @Date: 2016-08-18 17:46:19
* @Last Modified by: printempw
* @Last Modified time: 2016-10-16 20:23:12
*/
use App\Models\UserModel;
use App\Models\Player;
use App\Models\Closet;
use App\Models\Texture;
if (!defined('BASE_DIR')) exit('Permission denied.');
$v2_table_name = $_POST['v2_table_name'];
$prefix = get_db_config()['prefix'];
$v3_users = $prefix."users";
$v3_players = $prefix."players";
$v3_closets = $prefix."closets";
$v3_textures = $prefix."textures";
$user_imported = 0;
$user_duplicated = 0;
$texture_imported = 0;
$texture_duplicated = 0;
// use db helper instead of fat ORM in some operations :(
$db = Database::table($v2_table_name, true);
$steps = ceil($db->getRecordNum() / 250);
$score = Option::get('user_initial_score');
$public = isset($_POST['import_as_private']) ? '0' : '1';
// chunked (optionally)
for ($i = 0; $i <= $steps; $i++) {
$start = $i * 250;
$sql = "SELECT * FROM `$v2_table_name` ORDER BY `uid` LIMIT $start, 250";
$result = $db->query($sql);
while ($row = $result->fetch_array()) {
// compile patterns
$name = str_replace('{username}', $row['username'], $_POST['texture_name_pattern']);
if (Player::where('player_name', $row['username'])->get()->isEmpty()) {
$user = new UserModel;
$user->email = '';
$user->nickname = $row['username'];
$user->score = $score;
$user->password = $row['password'];
$user->avatar = '0';
$user->ip = $row['ip'];
$user->permission = '0';
$user->last_sign_at = Utils::getTimeFormatted(time() - 86400);
$user->register_at = Utils::getTimeFormatted();
$user->save();
$models = ['steve', 'alex', 'cape'];
$textures = [];
foreach ($models as $model) {
if ($row["hash_$model"] != "") {
$name = str_replace('{model}', $model, $name);
$res = Texture::where('hash', $row["hash_$model"])->first();
if (!$res) {
$t = new Texture;
// file size in bytes
$size = Storage::disk('textures')->has($row["hash_$model"]) ? Storage::disk('textures')->size($row["hash_$model"]) : 0;
$t->name = $name;
$t->type = $model;
$t->likes = 1;
$t->hash = $row["hash_$model"];
$t->size = ceil($size / 1024);
$t->uploader = $user->uid;
$t->public = $public;
$t->upload_at = $row['last_modified'] ? : Utils::getTimeFormatted();
$t->save();
$textures[$model] = $t->tid;
$texture_imported++;
} else {
$textures[$model] = $res->tid;
$texture_duplicated++;
}
}
}
$p = new Player;
$p->uid = $user->uid;
$p->player_name = $row['username'];
$p->preference = $row['preference'];
$p->last_modified = $row['last_modified'] ? : Utils::getTimeFormatted();
$c = new Closet($user->uid);
$items = [];
foreach ($textures as $model => $tid) {
$property = "tid_$model";
$p->$property = $tid;
$items[] = array(
'tid' => $tid,
'name' => $name,
'add_at' => $row['last_modified'] ? : Utils::getTimeFormatted()
);
}
$c->setTextures(json_encode($items));
$user_imported++;
// echo $row['username']." saved. <br />";
} else {
$user_duplicated++;
// echo $row['username']." duplicated. <br />";
}
}
}
return [
'user' => [
'imported' => $user_imported,
'duplicated' => $user_duplicated
],
'texture' => [
'imported' => $texture_imported,
'duplicated' => $texture_duplicated
]
];

View File

@ -1,73 +0,0 @@
<?php
/**
* @Author: printempw
* @Date: 2016-08-09 21:44:13
* @Last Modified by: printempw
* @Last Modified time: 2016-09-14 19:44:30
*
* There are still some coupling relationships here but,
* Just let it go :)
*/
if (!defined('BASE_DIR')) exit('Permission denied.');
$v2_table_name = $_POST['v2_table_name'];
$v3_table_name = get_db_config()['prefix']."textures";
$imported = 0;
$duplicated = 0;
// use db helper instead of fat ORM
$db = Database::table($v2_table_name, true);
$steps = ceil($db->getRecordNum() / 250);
$public = isset($_POST['import_as_private']) ? '0' : '1';
// chunked (optionally)
for ($i = 0; $i <= $steps; $i++) {
$start = $i * 250;
$sql = "SELECT * FROM `$v2_table_name` ORDER BY `uid` LIMIT $start, 250";
$result = $db->query($sql);
while ($row = $result->fetch_array()) {
// compile patterns
$name = str_replace('{username}', $row['username'], $_POST['texture_name_pattern']);
$models = ['steve', 'alex', 'cape'];
foreach ($models as $model) {
if ($row['hash_steve'] != "") {
$name = str_replace('{model}', $model, $name);
if (!$db->has('hash', $row["hash_$model"], $v3_table_name)) {
// file size in bytes
$size = Storage::disk('textures')->has($row["hash_$model"]) ? Storage::disk('textures')->size($row["hash_$model"]) : 0;
$db->insert([
'name' => $name,
'type' => $model,
'likes' => 0,
'hash' => $row["hash_$model"],
'size' => ceil($size / 1024),
'uploader' => $_POST['uploader_uid'],
'public' => $public,
'upload_at' => Utils::getTimeFormatted()
], $v3_table_name);
$imported++;
// echo $row['hash_steve']." saved. <br />";
} else {
$duplicated++;
// echo $row['hash_steve']." duplicated. <br />";
}
}
}
}
}
return [
'imported' => $imported,
'duplicated' => $duplicated
];

View File

@ -1,77 +0,0 @@
<?php
/**
* @Author: printempw
* @Date: 2016-08-18 17:46:19
* @Last Modified by: printempw
* @Last Modified time: 2016-09-14 19:43:03
*/
if (!defined('BASE_DIR')) exit('Permission denied.');
$v2_table_name = $_POST['v2_table_name'];
$prefix = get_db_config()['prefix'];
$v3_users = $prefix."users";
$v3_players = $prefix."players";
$v3_closets = $prefix."closets";
$imported = 0;
$duplicated = 0;
// use db helper instead of fat ORM
$db = Database::table($v2_table_name, true);
$steps = ceil($db->getRecordNum() / 250);
$score = Option::get('user_initial_score');
// chunked (optionally)
for ($i = 0; $i <= $steps; $i++) {
$start = $i * 250;
$sql = "SELECT * FROM `$v2_table_name` ORDER BY `uid` LIMIT $start, 250";
$result = $db->query($sql);
while ($row = $result->fetch_array()) {
if (!$db->has('player_name', $row['username'], $v3_players)) {
// generate random nickname
$nickname = $row['username']."_".time();
$db->insert([
'email' => '',
'nickname' => $nickname,
'score' => $score,
'password' => $row['password'],
'avatar' => '0',
'ip' => $row['ip'],
'permission' => '0',
'last_sign_at' => Utils::getTimeFormatted(time() - 86400),
'register_at' => Utils::getTimeFormatted()
], $v3_users);
$uid = $db->select('nickname', $nickname, null, $v3_users)['uid'];
$db->insert([
'uid' => $uid,
'player_name' => $row['username'],
'preference' => $row['preference'],
'last_modified' => Utils::getTimeFormatted()
], $v3_players);
$db->insert([
'uid' => $uid,
'textures' => ''
], $v3_closets);
$imported++;
// echo $row['username']." saved. <br />";
} else {
$duplicated++;
// echo $row['username']." duplicated. <br />";
}
}
}
return [
'imported' => $imported,
'duplicated' => $duplicated
];

View File

@ -1,57 +0,0 @@
<?php
/**
* Migrations Bootstrap of Blessing Skin Server
*/
require dirname(__DIR__)."/includes/bootstrap.php";
// If already installed
if (!check_table_exists()) {
redirect_to('../index.php');
}
// load session from cookie
if (isset($_COOKIE['uid']) && isset($_COOKIE['token'])) {
$_SESSION['uid'] = $_COOKIE['uid'];
$_SESSION['token'] = $_COOKIE['token'];
}
// check permission
if (isset($_SESSION['uid'])) {
$user = $app['users']->get($encrypter->decrypt($_COOKIE['uid']));
if ($_SESSION['token'] != $user->getToken())
redirect_to('../../auth/login', '无效的 token请重新登录~');
if ($user->getPermission() != App\Models\User::SUPER_ADMIN)
abort(403, '此页面仅超级管理员可访问');
} else {
redirect_to('../../auth/login', '非法访问,请先登录');
}
$action = isset($_GET['action']) ? $_GET['action'] : 'index';
switch ($action) {
case 'index':
View::show('setup.migrations.index');
break;
case 'import-v2-textures':
View::show('setup.migrations.import-v2-textures');
break;
case 'import-v2-users':
View::show('setup.migrations.import-v2-users');
break;
case 'import-v2-both':
View::show('setup.migrations.import-v2-both');
break;
default:
throw new App\Exceptions\PrettyPageException('非法参数', 1, true);
break;
}
Session::save();

View File

@ -1,67 +0,0 @@
<?php
/**
* Update Bootstrap of Blessing Skin Server
*/
require __DIR__."/includes/bootstrap.php";
// If no update is available
if (config('app.version') == Option::get('version', '')) {
View::show('setup.locked');
exit;
}
$step = isset($_GET['step']) ? $_GET['step'] : '1';
switch ($step) {
case '1':
View::show('setup.updates.welcome');
break;
case '2':
$resource = opendir(BASE_DIR."/setup/update_scripts/");
$update_script_exist = false;
$tips = [];
while($filename = @readdir($resource)) {
if ($filename != "." && $filename != "..") {
preg_match('/update-(.*)-to-(.*).php/', $filename, $matches);
if (isset($matches[2])) {
$update_script_exist = ($matches[2] == config('app.version'));
} else {
continue;
}
$result = require BASE_DIR."/setup/update_scripts/$filename";
if (is_array($result)) {
// push tip to array
foreach ($result as $tip) {
$tips[] = $tip;
}
}
}
}
closedir($resource);
foreach (config('options') as $key => $value) {
if (!Option::has($key))
Option::set($key, $value);
}
if (!$update_script_exist) {
// if update script is not given
Option::set('version', config('app.version'));
}
View::show('setup.updates.success', ['tips' => $tips]);
break;
default:
throw new App\Exceptions\PrettyPageException('非法参数', 1, true);
break;
}