2024-08-31 01:03:37 +08:00

1067 lines
42 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* 初始化项目基础数据
* 需先创建数据库建表并配置好config/setting_user.php
*/
class installIndex extends Controller {
public $roleID;
public $admin = array();
public $userSetting;
public $installLock;
public $dbType;
public $engine;
public function __construct() {
parent::__construct();
$this->userSetting = BASIC_PATH . 'config/setting_user.php';
$this->installLock = USER_SYSTEM . 'install.lock';
$this->installFastLock = USER_SYSTEM . 'fastinstall.lock'; // 旧版
$this->authCheck();
}
// 请求权限检测
public function authCheck(){
if(MOD.'.'.ST == 'install.index'){
if(!ACT || !in_array(ACT, array('env', 'save', 'auto'))){
show_json(LNG('common.illegalRequest'), false);
}
$check = $this->initCheck();
if(ACT == 'auto') $this->cliInstall($check); // cli自动安装
if($check === 2) show_json(LNG('admin.install.errorRequest'), false);
}
}
// 安装配置初始化检测
private function initCheck(){
if(!defined('STATIC_PATH')){
define('STATIC_PATH',$GLOBALS['config']['settings']['staticPath']);
}
if(!defined('INSTALL_PATH')){
define('INSTALL_PATH', CONTROLLER_DIR.'install/');
}
// 1.setting_user.php、install.lock、数据库配置都存在已安装
// 2.setting_user.php、数据库配置存在install.lock不存在重置管理员密码
if(@file_exists($this->userSetting)) {
if($this->defDbConfig(true)) {
// if(@file_exists($this->installLock)) return true;
return @file_exists($this->installLock) ? 2 : 1;
} else {
del_file($this->userSetting);
}
}
if(!@file_exists($this->userSetting)) del_file($this->installLock);
// return false;
return 0;
}
// 安装检测
public function check(){
// 判断是否需要安装
if($this->initCheck() === 2) return;
if(ACTION == 'user.view.call'){exit;}
if(ACTION == 'user.view.options'){
$options = array(
"kod" => array(
'systemOS' => $this->config['systemOS'],
'phpVersion' => PHP_VERSION,
'appApi' => appHostGet(),
'APP_HOST' => APP_HOST,
'ENV_DEV' => !!STATIC_DEV,
'staticPath' => STATIC_PATH,
'version' => KOD_VERSION,
'build' => KOD_VERSION_BUILD,
'channel' => INSTALL_CHANNEL,
),
"user" => array('config' => array()),
"io" => array(),
"lang" => I18n::getType(),
);
if($this->in['full'] == '1'){
$options['_lang'] = array(
"list" => I18n::getAll(),
"lang" => I18n::getType(),
);
}
show_json($options);
}
$actions = array(
'install.index.env',
'install.index.save',
'user.view.lang',
);
if( in_array(ACTION, $actions) ){
ActionCall(ACTION);exit;
}
// 安装路径合法性检测; 不允许[, ;%][*][&=+%#?{}]; 允许(_!@$[]()-./); 需要转义([]@$)
$uri = str_replace(HOST,'',APP_HOST);$matchArr = array();
if($uri && !preg_match("/^[a-zA-Z0-9_!@$\[\]\(\)\-\.\/]*$/",$uri,$matchArr)){
show_tips("App path cann't has special chars<br/>(".LNG('admin.install.pathErrDesc').")<pre>".$uri.'</pre>');
}
$this->tpl = CONTROLLER_DIR . 'install/static/';
$value = array(
'installPath' => APP_HOST.'app/controller/install/static/',
'envList' => $this->envList(),
'installFast' => @file_exists($this->userSetting) ? 1 : 0, // 是否已安装setting_user.php存在
'installAuto' => '' // 管理员账号名
);
// 获取管理员账号
if ($value['installFast']) {
try{
$info = Model('User')->find('1');
if (!empty($info['name'])) $value['installAuto'] = $info['name'];
}catch(Exception $e){}
}
$this->values = $value;
$this->display('index.html');
exit;
}
private function envList(){
$opts = array(
'path_writable' => array('title' => LNG('admin.install.dirRight'), 'text' => LNG('admin.install.pathNeedWirte')),
'php_version' => array('title' => 'PHP '.LNG('common.version'), 'text' => LNG('admin.install.phpVersionTips')),
'allow_url_fopen' => array('text' => LNG('admin.install.mustOpen')),
'php_bit' => array('title' => 'PHP '.LNG('common.sysVersion'), 'text' => LNG('admin.install.phpBitTips').'<br/><span class="bit-desc">('.LNG('admin.install.phpBitDesc').')</span>'),
'iconv' => array(),
'mb_string' => array(),
'json' => array(),
'curl' => array(),
'xml' => array(),
'shell_exec' => array('title' => 'shell_exec、exec '.LNG('common.method')),
'gd' => array(),
'path_list' => array('title' => LNG('admin.install.serverDir'), 'text' => LNG('admin.install.suggestClose'))
);
foreach ($opts as $key => &$opt) {
$opt['title'] = _get($opt, 'title', strtoupper($key).' '.LNG('common.extend'));
$opt['text'] = _get($opt, 'text', LNG('admin.install.suggestOpen'));
}
return $opts;
}
/**
* cli一键安装
* php /usr/local/var/www/kod/kodbox/index.php "install/index/auto"
* --database mysql --database-name "kodbox" --database-user "root" --database-pass "root" --database-host "127.0.0.1:3306"
* --database sqlite // or
* --cache redis --redis-host "127.0.0.1" --redis-port "6379" --redis-auth "1234" // 不传递是默认文件缓存
* --user-name "admin" --user-pass "admin"
* --db-del 1/0 // 数据表已存在,是否删除/保留,默认保留
* --user-auto 1 // 随机密码admin/xxx
* --user-reset 1 // 重置管理员密码
* --language en // 默认为中文
* @return void
*/
public function cliInstall($check=0) {
if (!is_cli() || !isset($_SERVER['argv'])) return;
// 接管show_tips
Hook::bind('show_tips', array($this, 'cliShowTips'));
// 切换英文——会导致系统以英文初始化
if ($this->cliArgs('language') == 'en' && I18n::getType() != 'en') {
$array = include(LANGUAGE_PATH.'en/index.php');
if (!empty($array)) I18n::set($array);
}
// 已安装
if ($check === 2) $this->cliEcho(LNG('admin.install.errorRequest'));
// 获取一键安装参数
$action = _get($this->in, 'action', '');
if ($action && in_array($action, array('db', 'user'))) return; // 避免自动安装死循环——ACT=auto
$data = $this->cliInstallData();
//0.非重置账号检测db参数及配置——仅新版支持参数检查、重置密码
if (!isset($this->cliInstVer)) {
if (!$this->cliMore('reset')) {
if (!$check && empty($data['db'])) {
$this->cliEcho(LNG('common.invalidParam'));
}
// db配置已存在禁止再次执行
if ($check === 1) {
$msg = PHP_EOL.LNG('admin.install.dbWasSet').PHP_EOL;
$txt = empty($data['user']['pass']) ? '--user-name "'.LNG('user.account').'" --user-pass "'.LNG('common.password').'" ' : '';
$msg .= LNG('admin.install.ifResetAuto').$txt.'--user-reset 1';
$this->cliEcho($msg);
}
} else {
if (!$check) $this->cliEcho(LNG('admin.install.resetSysErr'));
$this->cliSaveUser($data); exit;
}
}
// 1.提交数据库设置——成功后自动提交管理员设置
$this->cliSaveDb($data);
}
// 1.自动提交数据库保存
public function cliSaveDb($data){
$self = $this;
$init = array(
'action' => 'db',
'del' => $this->cliMore('del') ? 1 : 0
);
$this->in = array_merge($init, $data['db']);
ActionCallResult("install.index.save",function(&$res) use($self,$data){
$msg = str_replace('<br/>',PHP_EOL,$res['data']);
if (!$res['code']) {
// 数据库已存在且有表视作自行导入的kod库暂不做对比检测
if (_get($res,'info') == 10001) {
$keep = !$self->cliMore('del'); // 默认保留del=0/null
if (!$keep) { // 不保留——执行不到这里:默认保留($keep不保留del=1会直接删除不返回info=10001
$msg = LNG('admin.install.ifDelDbAuto');
$msg = str_replace('[1]', '['._get($data,'db.dbName','').']', $msg);
} else {
// 添加配置文件——旧版存在,新版不存在
if (!isset($self->cliInstVer)) $self->cliUserSetting($data['db']);
}
} else {
$self->cliEcho($msg);
}
}
// $msg = stristr(I18n::getType(),'zh') ? '数据库配置完成!' : 'Database configuration completed!'; // LNG('admin.install.dbSetOk')
$self->cliEcho('1.Database configuration completed!',true,false);
// 2.执行成功,写入管理员账号
$self->cliSaveUser($data);
});
}
// 保存数据库配置文件
private function cliUserSetting($db) {
$type = _get($db, 'cacheType', 'file');
$cache = array('type' => $type);
if ($type != 'file') {
$cache['host'] = _get($db, $type.'Host', '');
$cache['port'] = _get($db, $type.'Port', '');
if ($type == 'redis' && !empty($db['redisAuth'])) {
$cache['auth'] = $db['redisAuth'];
}
}
$data = $this->dbConfig();
$this->setUserSetting($data, $cache);
}
// 2.自动提交管理员保存(系统初始化)
public function cliSaveUser($data) {
$name = _get($data, 'user.name', '');
$pass = _get($data, 'user.pass', '');
// 非重置账号没有传递账号密码时提醒在web访问设置
if (!$this->cliMore('reset') && (empty($name) || empty($pass))) {
del_file($this->installFastLock);
$this->cliEcho(LNG('admin.install.userOnWeb'), true);
}
$this->in = array(
'name' => $name,
'password' => $pass,
'action' => 'user'
);
$self = $this;
ActionCallResult("install.index.save",function(&$res) use($self,$name,$pass){
if (!$res['code']) {
$msg = str_replace('<br/>',PHP_EOL,$res['data']);
$self->cliEcho(LNG('admin.install.userSaveErr').$msg);
}
del_file($self->installFastLock);
if (!$self->cliMore('reset')) {
// $msg = stristr(I18n::getType(),'zh') ? '系统初始化完成!' : 'System initialization completed!'; // LNG('admin.install.userSetOk')
$self->cliEcho('2.System initialization completed!',true,false);
}
$msg = LNG('admin.install.autoPwdTips').$name.' '.$pass;
if (!$self->cliMore('auto')) $msg = ''; // 仅自动生成密码时,在回复中显示
$self->cliEcho($msg, true);
});
}
// 获取自动安装配置参数
private function cliInstallData(){
if (empty($_SERVER['argv']) || !is_array($_SERVER['argv'])) return;
$this->cliInstallOld(); // 兼容旧版
$args = $this->cliArgs();
if (empty($args)) return;
$this->cliMore($args);
// 1.检查参数非重置密码时检查db、缓存重置时忽略数据库、缓存要求系统已完成初始化
$dbType = _get($args, 'database', '');
$ccType = _get($args, 'cache', 'file');
if (!$this->cliMore('reset')) {
if (!$dbType || !in_array($dbType, array('mysql', 'sqlite'))) {
$this->cliEcho(LNG('common.invalidParam').' database');
}
if (!in_array($ccType, array('file', 'redis', 'memcached'))) {
$this->cliEcho(LNG('common.invalidParam').' cache');
}
}
// 2.构建前端提交的参数样式
$db = $user = array();
$db['dbType'] = $dbType;
$db['cacheType'] = $ccType;
foreach ($args as $key => $value) {
$arr = explode('-', $key);
if (empty($arr[1])) continue;
$tmp = $arr[0];
// 管理员
if ($tmp == 'user') {
$user[$arr[1]] = $value;
continue;
}
// 数据库、缓存
if ($tmp == 'database') {
$tmp = 'db';
if ($arr[1] == 'pass') $arr[1] = 'pwd';
}
$db[$tmp.ucfirst($arr[1])] = $value;
}
// redis、memcached端口赋默认值
if ($ccType != 'file' && empty($db[$ccType.'Port'])) {
$db[$ccType.'Port'] = $ccType == 'redis' ? '6379' : '11211';
}
if ($dbType == 'mysql') $db['dbEngine'] = 'innodb';
// 3.账号密码
if (empty($user['name'])) $user['name'] = 'admin'; // 不传递默认为admin——重置时应该从数据库读取暂不处理
if ($this->cliMore('auto')) {
$user['pass'] = 'K0d#'.rand_string(6);
} else {
// 重置且非自动时,要求必须填写密码
if ($this->cliMore('reset') && empty($user['pass'])) {
$this->cliEcho(LNG('admin.install.resetPwdTips'));
}
}
// 4.重置用户,数据库、缓存置为空
if ($this->cliMore('reset')) $db = array();
return array('db' => $db, 'user' => $user);
}
private function cliArgs($key=false){
$argv = $_SERVER['argv'];
if (!is_array($argv)) return array();
array_shift($argv);
array_shift($argv); // 移除前2个参数./index.php、install/index/auto
$name = null;
$args = array();
foreach ($argv as $arg) {
if (substr($arg, 0, 1) == '-') {
$name = ltrim($arg, '-');
} else {
if ($name) {
$args[$name] = $arg;
$name = null;
}
}
}
return $key ? _get($args, $key) : $args;
}
// 获取cli调用附加参数
private function cliMore($key=false) {
if (!$key) unset($GLOBALS['AUTO_INSTALL_IN_MORE']);
if (is_string($key)) {
$val = _get($GLOBALS, 'AUTO_INSTALL_IN_MORE.'.$key, 0);
return $val == '1' ? true : false;
}
$args = $key;
$GLOBALS['AUTO_INSTALL_IN_MORE'] = array(
'del' => _get($args,'db-del',0), // 数据表删除/保留
'auto' => _get($args,'user-auto',0), // 管理员随机密码
'reset' => _get($args,'user-reset',0), // 管理员密码重置
);
}
// 命令行中输出结果——换行
private function cliEcho($msg, $code=false, $prfx=true) {
// $pre = !$this->cliMore('reset') ? 'admin.install.' : 'explorer.';
// echo ($prfx ? LNG($pre.($code ? 'success' : 'error')).' ' : '').$msg.PHP_EOL;
echo ($code ? 'Success! ' : 'Error! ').$msg.PHP_EOL;
if ($prfx) exit;
}
// 捕获show_tips错误直接输出信息——开启debug时无效pr输出
public function cliShowTips($message,$url, $time,$title) {
$msg = ''; // think_exception输出html
// if (stripos($message,'<div class="desc"') >= 0) {
if (stripos($message,'<div') >= 0) {
$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($message, 'HTML-ENTITIES', 'UTF-8'));
// $xpath = new DOMXPath($dom);
// $elements = $xpath->query('//div[@class="desc"]');
// if (!is_null($elements)) $msg = $elements[0]->nodeValue;
foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $node) {
$msg .= $node->nodeValue.PHP_EOL;
}
$msg = rtrim($msg, PHP_EOL);
}
if (!$msg) $msg = $message;
$this->cliEcho($msg);
}
/**
* cli一键安装兼容旧版
* 根据fastinstall.lock判断默认包含数据库和配置文件以此构建argv参数以适配新版逻辑
* @return void
*/
public function cliInstallOld(){
$file = $this->installFastLock;
if (!@file_exists($file)) return; // KOD_VERSION >= 1.52
if (!@file_exists($this->userSetting)) $this->cliEcho('Invalid configuration file (config/setting_user.php).');
$this->cliInstVer = 'old';
// 构建argv参数
$data = array();
$db = $this->config['database'];
$cc = $this->config['cache'];
// 数据库
if (stripos($db['DB_TYPE'],'sqlite') === 0) {
$data = array('--database', 'sqlite');
} else {
$data = array(
'--database', 'mysql',
'--database-host',
$db['DB_HOST'].':'._get($db,'DB_PORT',3306),
'--database-user',
$db['DB_USER'],
'--database-pass',
$db['DB_PWD'],
'--database-name',
$db['DB_NAME'],
);
}
// 缓存
$ccType = _get($cc, 'cacheType', 'file');
if (in_array($ccType, array('redis', 'memcached'))) {
$data[] = '--cache';
$data[] = $ccType;
$data[] = '--'.$ccType.'-host';
$data[] = _get($cc, $ccType.'.host','');
$data[] = '--'.$ccType.'-port';
$data[] = _get($cc, $ccType.'.port','');
if ($ccType == 'redis' && !empty($cc['redis']['auth'])) {
$data[] = '--redis-auth';
$data[] = $cc['redis']['auth'];
}
}
// 管理员
$user = $this->getFastAcc($file);
if ($user) {
$data[] = '--user-name';
$data[] = $user['name'];
$data[] = '--user-pass';
$data[] = $user['pass'];
}
$_SERVER['argv'] = array_merge($_SERVER['argv'], $data);
}
// 获取自动安装账号密码
private function getFastAcc($file){
$content = trim(file_get_contents($file));
if(empty($content)) return false;
$data = array();
$content = array_filter(explode(PHP_EOL, $content));
foreach($content as $line) {
$tmp = explode("=", trim($line));
if(empty(trim($tmp[1]))) continue;
$data[strtolower(trim($tmp[0]))] = trim($tmp[1]);
}
if(isset($data['adm_name']) && isset($data['adm_pwd'])) {
return array(
'name' => $data['adm_name'],
'pass' => $data['adm_pwd']
);
}
return false;
}
/**
* 获取数据库默认配置信息
* @param boolean $return false:表单数据;true:db配置数据
* @return void
*/
public function defDbConfig($return=false){
$data = array();
// 1.获取文件数据
if(!$dbConfig = $this->config['database']) return $data;
if(!$dbConfig['DB_TYPE']) return $data;
if($return) return $dbConfig;
// 2.解析为form表单数据
$database = array();
unset($dbConfig['DB_SQL_LOG'],$dbConfig['DB_FIELDS_CACHE'],$dbConfig['DB_SQL_BUILD_CACHE']);
foreach($dbConfig as $key => $value) {
$keys = explode("_", strtolower($key));
$key = $keys[0] . ucfirst($keys[1]);
$database[$key] = $value;
}
// 2.1 pdo数据处理
if($database['dbType'] == 'pdo') {
$dsn = explode(":", $database['dbDsn']);
$database['pdoType'] = $dsn[0];
unset($database['dbDsn']);
foreach($database as $key => $value) {
if(in_array($key, array('dbType', 'pdoType'))) continue;
$database['pdo'.ucfirst($key)] = $value;
unset($database[$key]);
}
}
if($database['dbType'] == 'mysqli') $database['dbType'] = 'mysql';
if(in_array($database['dbType'], array('sqlite', 'sqlite3'))) {
if($database['dbType'] == 'sqlite3') $database['dbType'] = 'sqlite';
$database['dbName'] = '';
}
if(!$cache = $this->config['cache']) return $database; // 无cache
$cacheType = $cache['cacheType'];
$database['cacheType'] = $cacheType;
if($cacheType == 'file') return $database; // 文件cache
$database[$cacheType.'Host'] = $cache[$cacheType]['host'];
$database[$cacheType.'Port'] = $cache[$cacheType]['port'];
return $database;
}
// 环境检测
public function env(){
if(isset($this->in['db']) && $this->in['db'] == 1) {
$data = $this->defDbConfig();
show_json($data);
}
$env = array(
'path_writable' => array(),
'php_version' => phpversion(),
'allow_url_fopen' => ini_get('allow_url_fopen') == '1',
'php_bit' => phpBuild64() ? 64 : 32,
'iconv' => function_exists('iconv'),
'mb_string' => function_exists('mb_convert_encoding'),
'json' => function_exists('json_encode'),
'curl' => function_exists('curl_init'),
'xml' => function_exists('xml_parser_create'),
'shell_exec' => (function_exists('shell_exec') && function_exists('exec')),
'gd' => true,
'path_list' => check_list_dir(),
);
if( !function_exists('imagecreatefromjpeg')||
!function_exists('imagecreatefromgif')||
!function_exists('imagecreatefrompng')||
!function_exists('imagecolorallocate')){
$env['gd'] = false;
}
$pathWrt = true;
$pathList = array(BASIC_PATH, DATA_PATH, DATA_PATH.'system');
foreach ($pathList as $value) {
if(!path_writeable($value)) $pathWrt = false;
break;
}
$env['path_writable'] = $pathWrt ? $pathWrt : rtrim(BASIC_PATH, '/');
show_json($env);
}
/**
* 数据库、管理员账号提交
*
* @return void
*/
public function save(){
$action = Input::get('action', 'in', null, array('db', 'user'));
if ($action == 'db') {
$this->saveDb();
} else {
$this->saveUser();
}
}
/**
* 1. 数据库配置
*/
private function saveDb(){
// 1.1 获取db配置信息
$data = $this->dbConfig();
if (isset($dat['code']) && !$data['code']) return $data;
$dbName = $data['DB_NAME'];
$cacheType = Input::get('cacheType', 'in', null, array('file', 'redis', 'memcached'));
// 1.2 连接数据库
// 如果用include引入配置文件$config的值会是上次请求的所以直接用$data赋值
$GLOBALS['config']['database'] = $data;
// $GLOBALS['config']['cache']['sessionType'] = $cacheType;
// $GLOBALS['config']['cache']['cacheType'] = $cacheType;
think_config($GLOBALS['config']['databaseDefault']);
think_config($GLOBALS['config']['database']);
if($this->dbType == 'mysql'){
// mysql连接先不指定数据库配置错误时会报错
$GLOBALS['config']['database']['DB_NAME'] = '';
think_config($GLOBALS['config']['database']);
$db = Model()->db();
$dbexist = $db->execute("show databases like '{$dbName}'");
}
$GLOBALS['config']['database']['DB_NAME'] = $dbName; // 避免auto调用时后续取该值为空同一进程
// 1.3 检测缓存配置
// 判断所需缓存配置是否有效——redis、memcached
if(in_array($cacheType, array('redis', 'memcached'))){
if(!extension_loaded($cacheType)){
return show_json(sprintf(LNG('common.env.invalidExt'), "[php-{$cacheType}]"), false);
}
$host = Input::get("{$cacheType}Host", 'require');
$port = Input::get("{$cacheType}Port", 'require');
$type = ucfirst($cacheType);
$handle = new $type();
try{
if($cacheType == 'redis') {
$handle->connect($host, $port, 1);
$auth = Input::get('redisAuth');
if ($auth) $handle->auth($auth);
$conn = $handle->ping();
}else{
$conn = $handle->addServer($host, $port);
if($conn && !$handle->getStats()) $conn = false;
}
if(!$conn) return show_json(sprintf(LNG('admin.install.cacheError'),"[{$cacheType}]"), false);
}catch(Exception $e){
$msg = sprintf(LNG('admin.install.cacheConnectError'),"[{$cacheType}]");
$msg .= '<br/>'.$e->getMessage();
return show_json($msg, false);
}
}
// 1.4 创建数据库
if($this->dbType == 'mysql'){
if(!$dbexist){
// host=localhost时root空密码默认没有权限会创建失败
$db->execute("create database `{$dbName}`");
}
$db->execute("use `{$dbName}`");
$tables = $db->getTables($dbName);
if (!empty($tables)) {
if(!isset($this->in['del']) || $this->in['del'] != '1'){
return show_json(LNG('admin.install.ifDelDb'), false, 10001);
}
// 删除数据表
foreach($tables as $table) {
if ($table) {
$table = strtolower($table);
} else {continue;}
$db->execute("drop table if exists `{$table}`");
}
}
}else{
$db = Model()->db();
}
// 1.5 写入配置文件:数据库、缓存
$data['DB_NAME'] = $dbName;
$cache = array('type' => $cacheType);
if (isset($host) && isset($port)) {
$cache['host'] = $host;
$cache['port'] = $port;
if (!empty($auth)) $cache['auth'] = $auth;
}
$this->setUserSetting($data, $cache);
// 1.6 创建数据表
$res = $this->createTable($db);
if (isset($res['code']) && !$res['code']) return $res;
return show_json(LNG('explorer.success'));
}
private function sqliteFilter($content) {
$replaceFrom = "'DB_NAME' => '".USER_SYSTEM;
$replaceTo = "'DB_NAME' => USER_SYSTEM.'";
$replaceFrom2= "'DB_DSN' => 'sqlite:".USER_SYSTEM;
$replaceTo2 = "'DB_DSN' => 'sqlite:'.USER_SYSTEM.'";
$content = str_replace($replaceFrom,$replaceTo,$content);
$content = str_replace($replaceFrom2,$replaceTo2,$content);
return $content;
}
// 写入配置文件setting_user.php
private function setUserSetting($data, $cache){
if($data['DB_TYPE'] == 'pdo'){
$dbDsn = explode(':', $data['DB_DSN']);
if($dbDsn[0] == 'mysql'){
$data['DB_DSN'] .= ';dbname=' . $data['DB_NAME'];
}
}
$database = var_export($data, true);
$ccType = $cache['type'];
$text = array(
"<?php ",
"\$config['database'] = {$database};",
"\$config['cache']['sessionType'] = '{$ccType}';",
"\$config['cache']['cacheType'] = '{$ccType}';"
);
if(isset($cache['host'])){
$text[] = "\$config['cache']['{$ccType}']['host'] = '".$cache['host']."';";
$text[] = "\$config['cache']['{$ccType}']['port'] = '".$cache['port']."';";
if (isset($cache['auth'])) {
$text[] = "\$config['cache']['{$ccType}']['auth'] = '".$cache['auth']."';";
}
}
$file = $this->userSetting;
if(!@file_exists($file)) @touch($file);
$content = file_get_contents($file);
$pre = '';
if(stripos(trim($content),"<?php") !== false) {
$pre = PHP_EOL;
unset($text[0]);
}
$content = implode(PHP_EOL, $text);
if($this->dbType == 'sqlite') {
$content = $this->sqliteFilter($content);
}
if(!file_put_contents($file,$pre.$content, FILE_APPEND)) {
$msg = LNG('admin.install.dbSetError');
$tmp = explode('<br/>', LNG('common.env.pathPermissionError'));
$msg .= "<br/>" . $tmp[0];
return show_json($msg, false, 10000);
}
}
/**
* 创建数据表
* @param [type] $db
* @return void
*/
private function createTable($db){
$dbFile = INSTALL_PATH . "data/{$this->dbType}.sql";
if (!@file_exists($dbFile)) {
return show_json(LNG('admin.install.dbFileError'), false);
}
$content = file_get_contents($dbFile);
if($this->dbType == 'mysql') {
if(!empty($this->engine) && $this->engine == 'innodb') {
$content = str_ireplace('MyISAM', 'InnoDB', $content);
}
// fulltext索引兼容
$res = $db->query('select VERSION() as v');
$mysqlVersion = floatval(($res[0] && isset($res[0]['v'])) ? $res[0]['v'] : 0);
if($mysqlVersion && $mysqlVersion >= 5.7){
// 删除索引不存在时报错; 需手动处理;
//$content .= "\n".file_get_contents(INSTALL_PATH."data/fulltext.sql");
}else{
$content = str_ireplace('FULLTEXT ','', $content);
}
}
$sqlArr = sqlSplit($content);
foreach($sqlArr as $sql){
$db->execute($sql);
}
}
/**
* 获取数据库配置信息
*/
private function dbConfig(){
$this->dbType = $dbType = Input::get('dbType', 'in', null, array('sqlite', 'mysql', 'pdo'));
$dbList = $this->dbList();
$init = array('db_type' => $dbType);
if($dbType == 'mysql'){
$data = Input::getArray(array(
'dbHost' => array('aliasKey' => 'db_host', 'check' => 'require'),
'db_port' => array('default' => 3306),
'dbUser' => array('aliasKey' => 'db_user', 'check' => 'require'),
'dbPwd' => array('aliasKey' => 'db_pwd', 'check' => 'require', 'default' => ''),
'dbName' => array('aliasKey' => 'db_name', 'check' => 'require'),
));
$this->execPort($data);
$dbType = in_array('mysqli', $dbList) ? 'mysqli' : 'mysql';
$this->engine = Input::get('dbEngine', null, 'myisam');
}else if($dbType == 'pdo'){
$this->dbType = $pdoType = Input::get('pdoType', 'in', null, array('sqlite', 'mysql'));
if($pdoType == 'mysql'){
$data = Input::getArray(array(
'db_dsn' => array('default' => ''),
'pdoDbHost' => array('aliasKey' => 'db_host', 'check' => 'require'),
'db_port' => array('default' => 3306),
'pdoDbUser' => array('aliasKey' => 'db_user', 'check' => 'require'),
'pdoDbPwd' => array('aliasKey' => 'db_pwd', 'check' => 'require', 'default' => ''),
'pdoDbName' => array('aliasKey' => 'db_name', 'check' => 'require'),
));
$this->execPort($data);
$data['db_dsn'] = "mysql:host={$data['db_host']}";
$this->engine = Input::get('pdoDbEngine', null, 'myisam');
}else{
$data['db_dsn'] = "sqlite:" . $this->sqliteDbFile();
}
$dbType .= '_' . $pdoType;
}else{
$dbType = in_array('sqlite3', $dbList) ? 'sqlite3' : 'sqlite';
$data = array('db_name' => $this->sqliteDbFile());
}
if(!in_array($dbType, $dbList)){
if(stripos($dbType, 'sqlite') === 0 ||
(isset($data['db_dsn']) && stripos($data['db_dsn'], 'sqlite') === 0)) {
del_file($data['db_name']);
}
return show_json(sprintf(LNG('admin.install.dbTypeError'),$dbType), false);
}
if($init['db_type'] != 'pdo') $init['db_type'] = $dbType;
return array_change_key_case(array_merge($init, $data, array(
'DB_SQL_LOG' => true, // SQL执行错误日志记录
'DB_FIELDS_CACHE' => true, // 启用字段缓存
'DB_SQL_BUILD_CACHE' => false, // sql生成build缓存
)), CASE_UPPER);
}
private function execPort(&$data) {
$host = explode(':', $data['db_host']);
if(isset($host[1])) {
$data['db_host'] = $host[0];
$data['db_port'] = $host[1];
}
}
/**
* sqlite database文件
*/
private function sqliteDbFile(){
@chmod(DATA_PATH, 0755);
$dbFile = USER_SYSTEM . rand_string(12) . '.php';
@touch($dbFile);
return $dbFile;
}
/**
* 支持的数据库类型列表
* @return void
*/
private function dbList(){
$data = array('sqlite', 'sqlite3', 'mysql', 'mysqli', 'pdo_sqlite', 'pdo_mysql');
$list = array_map(function($type){
if (extension_loaded($type)){
return $type;
}
}, $data);
return array_filter($list);
}
/**
* 2. 账号设置
* @return void
*/
private function saveUser(){
$data = Input::getArray(array(
'name' => array('check' => 'require'),
'password' => array('check' => 'require')
));
$this->checkDbInit();
$userID = 1;
if(Model('User')->find($userID)) {
if(!Model('User')->userEdit($userID, $data)) {
show_json(LNG('user.bindUpdateError'), false);
}
@touch($this->installLock);
show_json(LNG('admin.install.updateSuccess'), true, $userID);
}
$this->admin = $data;
$this->sysInit();
}
// (检查)数据库初始化
private function checkDbInit(){
think_config($GLOBALS['config']['databaseDefault']);
// think_config($GLOBALS['config']['database']);
$data = $GLOBALS['config']['database'];
// 获取数据库类型,配置数据库信息(不指定数据库)
$type = $data['DB_TYPE'];
$dbName = $data['DB_NAME'];
switch ($data['DB_TYPE']) {
case 'pdo':
$dsn = explode(':', $data['DB_DSN']);
$type = $dsn[0];
$dsn = explode(';', $data['DB_DSN']);
$GLOBALS['config']['database']['DB_DSN'] = $dsn[0]; // 去掉数据库名
break;
case 'mysql':
case 'mysqli':
$type = 'mysql';
$GLOBALS['config']['database']['DB_NAME'] = '';
break;
case 'sqlite3':
$type = 'sqlite';
break;
}
think_config($GLOBALS['config']['database']);
// 判断数据库(表)是否存在
$db = Model()->db();
if ($type != 'sqlite') {
$exist = $db->execute("show databases like '{$dbName}'");
if (!$exist) show_json(LNG('ERROR_DB_NOT_EXIST'), false);
$db->execute("use `{$dbName}`");
}
// sqlite可直接调用该方法无论库文件是否存在
$tables = $db->getTables();
if (empty($tables) || !in_array('user', $tables)) {
$msg = $type == 'sqlite' ? 'dbError' : 'dbTableError';
show_json(LNG('admin.install.'.$msg), false);
}
// 重新配置数据库信息
$GLOBALS['config']['database'] = $data;
think_config($GLOBALS['config']['database']);
}
/**
* 初始化数据
*/
public function sysInit(){
define('USER_ID',1);
Cache::deleteAll();
$this->systemDefault();
$this->storageDefault();
$this->initLightApp();
$this->initPluginList();
$this->addGroup();
$this->addAuth();
$this->roleID = $this->getRoleID();
$this->addUser();
KodIO::initSystemPath();
@touch($this->installLock);
show_json(LNG('admin.install.createSuccess'), true);
}
/**
* 系统默认设置
*/
public function systemDefault(){
$default = $this->config['settingSystemDefault'];
$res = Model('SystemOption')->set($default);
if(!$res) show_json(LNG('admin.install.defSetError'), false);
}
/**
* 默认存储配置
*/
public function storageDefault(){
$driver = KodIO::defaultDriver();
if($driver) return $driver['id'];
$dataPath = './data/files/';
if(!is_dir($dataPath)) @mk_dir($dataPath);
$freeSize = @disk_free_space($dataPath);
$freeSize = $freeSize ? floor($freeSize / 1024 / 1024 / 1024) : 0;
$freeSize = $freeSize > 10 ? floor($freeSize / 10) * 10 : 10;
$data = array (
'name' => LNG('admin.storage.localStore'),
'sizeMax' => $freeSize,
'driver' => 'Local',
'default' => '1',
'system' => '1',
'config' => json_encode(array(
"basePath" => $dataPath
)),
);
$res = Model('Storage')->add($data);
if(!$res) show_json(LNG('admin.install.defStoreError'), false);
}
/**
* 轻应用列表初始化
*/
public function initLightApp(){
Action('explorer.lightApp')->initApp();
}
/**
* 初始化插件列表
*/
public function initPluginList(){
Model('Plugin')->viewList();
$list = Model('Plugin')->loadList();
foreach($list as $app => $item) {
Model('Plugin')->changeStatus($app, 1);
}
}
/**
* 添加根部门
*/
public function addGroup(){
$this->in = array(
"groupID" => 1,
"name" => $this->config['settingSystemDefault']['groupRootName'],
"sizeMax" => 0,
"parentID" => 0,
);
$res = ActionCallHook('admin.group.add');
if(!$res['code']){
show_json(LNG('admin.install.defGroupError'), false);
}
}
/**
* 文档权限
*/
public function addAuth(){
Model('Auth')->initData();
}
/**
* 系统内置角色
*/
public function getRoleID(){
$list = Model('SystemRole')->listData();
$roleList = array_to_keyvalue($list, 'administrator', 'id');
$administrator = 1;
if(!isset($roleList[$administrator])){
$roleID = $this->roleDefault();
if(!$roleID) show_json(LNG('admin.install.defRoleError'), false);
}else{
$roleID = $roleList[$administrator];
}
return $roleID;
}
/**
* 添加角色——Administrator、default
*/
private function roleDefault(){
$administrator = array (
'name' => LNG('admin.role.administrator'),
'display' => 1,
'system' => 1,
'administrator' => 1,
'auth' => 'explorer.add,explorer.upload,explorer.view,explorer.download,explorer.share,explorer.shareLink,explorer.remove,explorer.edit,explorer.move,explorer.serverDownload,explorer.search,explorer.unzip,explorer.zip,user.edit,user.fav,admin.index.dashboard,admin.index.setting,admin.index.loginLog,admin.index.log,admin.index.server,admin.role.list,admin.role.edit,admin.job.list,admin.job.edit,admin.member.list,admin.member.userEdit,admin.member.userAuth,admin.member.groupEdit,admin.auth.list,admin.auth.edit,admin.plugin.list,admin.plugin.edit,admin.storage.list,admin.storage.edit,admin.autoTask.list,admin.autoTask.edit',
'label' => 'label-green-deep',
'sort' => 2,
);
$groupOwner = array (
'name' => LNG('admin.role.group'),
'display' => 1,
'system' => 1,
'auth' => 'explorer.add,explorer.upload,explorer.view,explorer.download,explorer.share,explorer.shareLink,explorer.remove,explorer.edit,explorer.move,explorer.serverDownload,explorer.search,explorer.unzip,explorer.zip,user.edit,user.fav,admin.index.loginLog,admin.index.log,admin.member.list,admin.member.userEdit,admin.member.userAuth,admin.member.groupEdit,admin.auth.list',
'label' => 'label-blue-deep',
'sort' => 1,
);
$defaultUser = array (
'name' => LNG('admin.role.default'),
'display' => 1,
'system' => 1,
'auth' => 'explorer.add,explorer.upload,explorer.view,explorer.download,explorer.share,explorer.shareLink,explorer.remove,explorer.edit,explorer.move,explorer.serverDownload,explorer.search,explorer.unzip,explorer.zip,user.edit,user.fav',
'label' => 'label-blue-normal',
'sort' => 0,
);
Model('SystemRole')->add($defaultUser);
Model('SystemRole')->add($groupOwner);
$administrator = Model('SystemRole')->add($administrator);
return $administrator;
}
/**
* 新增用户-管理员
*/
public function addUser(){
$this->in = array(
"userID" => 1,
"name" => !empty($this->admin['name']) ? $this->admin['name'] : 'admin',
"nickName" => LNG('admin.role.administrator'),
"password" => !empty($this->admin['password']) ? $this->admin['password'] : 'admin',
"roleID" => $this->roleID,
"groupInfo" => json_encode(array('1'=>'1')),
"sizeMax" => 0,
);
$res = ActionCallHook('admin.member.add');
if(!$res) return;
if(!$res['code']){
show_json($res['data'], false);
}
}
}