charset_type_list = [ 'utf8mb4' => [ 'charset' => 'utf8mb4', 'collate' => 'utf8mb4_general_ci', 'version' => 5.6, ], 'utf8' => [ 'charset' => 'utf8', 'collate' => 'utf8_general_ci', 'version' => 5.0, ], ]; // 安装日志上报类库 $this->behavior_obj = new \base\Behavior(); } /** * 是否已安装 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ private function IsInstall() { // 是否已安装 if(file_exists(ROOT.'config/database.php')) { exit('你已经安装过该系统,重新安装需要先删除 ./config/database.php 文件'); } } /** * 协议 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Index() { $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'协议阅读']); return MyView(); } /** * 检查 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Check() { $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'环境检测']); return MyView(); } /** * 创建数据库 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Create() { $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'数据信息填写']); MyViewAssign('charset_type_list' , $this->charset_type_list); return MyView(); } /** * 完成 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Successful() { SystemService::SystemInstallCheck(); return MyView(); } /** * 确认、安装应用模块创建数据库配置文件 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Confirm() { // 是否ajax if(!IS_AJAX) { MyViewAssign('msg', '非法访问'); return MyView('public/error'); } // 参数 $params = input('post.'); $ret = $this->ParamsCheck($params); if($ret['code'] != 0) { $this->behavior_obj->ReportInstallLog(['msg'=>'参数校验['.$ret['msg'].']']); return $ret; } // 配置文件校验 if(file_exists(ROOT.'config/database.php')) { $this->behavior_obj->ReportInstallLog(['msg'=>'你已经安装过该系统,重新安装需要先删除[./config/database.php 文件]']); return DataReturn('你已经安装过该系统,重新安装需要先删除[./config/database.php 文件]', -1); } // 安装应用数据库配置文件生成 return $this->CreateDbConfig(APP_PATH.'install/config', $params); } /** * 安装 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description */ public function Add() { // 是否ajax if(!IS_AJAX) { MyViewAssign('msg', '非法访问'); return MyView('public/error'); } // 开始安装 $params = input('post.'); $db = $this->DbObj($params); if(!is_object($db)) { $this->behavior_obj->ReportInstallLog(['msg'=>'数据库连接失败']); return DataReturn('数据库连接失败', -1); } // mysql版本 $ret = $this->IsVersion($db, $params['DB_CHARSET']); if($ret['code'] != 0) { return $ret; } // 创建数据表 $ret = $this->CreateTable($db, $params); if($ret['code'] != 0) { return $ret; } // 生成数据库配置文件 $ret = $this->CreateDbConfig(ROOT.'config', $params); if($ret['code'] == 0) { $ret['msg'] = '安装成功'; $this->behavior_obj->ReportInstallLog(['msg'=>'安装成功']); } return $ret; } /** * 生成配置文件 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description * @param [string] $dir [目录地址] * @param [array] $params [输入参数] */ private function CreateDbConfig($dir, $params = []) { // 配置文件信息处理 $db_str=<< 'mysql', // 自定义时间查询规则 'time_query_rule' => [], // 自动写入时间戳字段 // true为自动识别类型 false关闭 // 字符串则明确指定时间字段类型 支持 int timestamp datetime date 'auto_timestamp' => true, // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', // 数据库连接配置信息 'connections' => [ 'mysql' => [ // 数据库类型 'type' => '{$params['DB_TYPE']}', // 服务器地址 'hostname' => '{$params['DB_HOST']}', // 数据库名 'database' => '{$params['DB_NAME']}', // 用户名 'username' => '{$params['DB_USER']}', // 密码 'password' => '{$params['DB_PWD']}', // 端口 'hostport' => '{$params['DB_PORT']}', // 数据库连接参数 'params' => [ \PDO::ATTR_CASE => \PDO::CASE_LOWER, \PDO::ATTR_EMULATE_PREPARES => true, ], // 数据库编码默认采用utf8mb4 'charset' => '{$params['DB_CHARSET']}', // 数据库表前缀 'prefix' => '{$params['DB_PREFIX']}', // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => false, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 是否严格检查字段是否存在 'fields_strict' => true, // 是否需要断线重连 'break_reconnect' => false, // 监听SQL 'trigger_sql' => true, // 开启字段缓存 'fields_cache' => false, ] ] ]; ?> php; if(@file_put_contents($dir.'/database.php', $db_str) === false) { $this->behavior_obj->ReportInstallLog(['msg'=>'配置文件创建失败['.$dir.']']); return DataReturn('配置文件创建失败', -1); } return DataReturn('操作成功', 0); } /** * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description * @param [object] $db [db对象] * @param [array] $params [输入参数] */ private function CreateTable($db, $params) { if(!file_exists(ROOT.'config/shopxo.sql')) { $this->behavior_obj->ReportInstallLog(['msg'=>'数据库sql文件不存在']); return DataReturn('数据库sql文件不存在', -1); } // sql文件 $sql = file_get_contents(ROOT.'config/shopxo.sql'); // 替换表前缀 if($params['DB_PREFIX'] != 'sxo_') { $sql = str_replace("`sxo_", " `{$params['DB_PREFIX']}", $sql); } // 编码替换处理 $charset = $this->charset_type_list[$params['DB_CHARSET']]; $charset_old = $this->charset_type_list[($charset['charset'] == 'utf8') ? 'utf8mb4' : 'utf8']; // 编码替换操作 $sql = str_replace("SET NAMES {$charset_old['charset']};", "SET NAMES {$charset['charset']};", $sql); $sql = str_replace("SET {$charset_old['charset']} ", "SET {$charset['charset']} ", $sql); $sql = str_replace("COLLATE {$charset_old['collate']} ", "COLLATE {$charset['collate']} ", $sql); $sql = str_replace(["SET = {$charset_old['charset']} ", "SET={$charset_old['charset']} "], "SET={$charset['charset']} ", $sql); $sql = str_replace(["COLLATE = {$charset_old['collate']} ", "COLLATE={$charset_old['collate']} "], "COLLATE={$charset['collate']} ", $sql); $sql = str_replace(["CHARSET = {$charset_old['charset']} ", "CHARSET={$charset_old['charset']} "], "CHARSET={$charset['charset']} ", $sql); $sql = str_replace($charset_old['collate'], $charset['collate'], $sql); // 转为数组 $sql_all = preg_split("/;[\r\n]+/", $sql); $success = 0; $failure = 0; foreach($sql_all as $v) { if (!empty($v)) { if($db->execute($v) !== false) { $success++; } else { $failure++; } } } $result = [ 'success' => $success, 'failure' => $failure, ]; $this->behavior_obj->ReportInstallLog(['msg'=>'sql运行 成功['.$success.']条, 失败['.$failure.']条']); if($failure > 0) { return DataReturn('sql运行失败['.$failure.']条', -1); } return DataReturn('success', 0, $result); } /** * 数据库版本校验 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description * @param [object] $db [db对象] * @param [string] $db_charset [数据库编码] */ private function IsVersion($db, $db_charset) { $data = $db->query('SELECT VERSION() AS `version`'); if(empty($data[0]['version'])) { $this->behavior_obj->ReportInstallLog(['msg'=>'查询数据库版本失败']); return DataReturn('查询数据库版本失败', -1); } else { $mysql_version = str_replace('-log', '', $data[0]['version']); if($mysql_version < $this->charset_type_list[$db_charset]['version']) { $msg = '数据库版本过低、需要>='.$this->charset_type_list[$db_charset]['version'].'、当前'.$mysql_version; $this->behavior_obj->ReportInstallLog(['msg'=>$msg, 'mysql_version'=>$mysql_version]); return DataReturn($msg, -1); } } return DataReturn('success', 0); } /** * 获取数据库操作对象 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description * @param array $params [输入参数] * @param string $db_name [数据库名称] */ private function DbObj($params = [], $db_name = '') { return Db::connect('mysql'); } /** * 参数校验 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-28 * @desc description * @param [array] $params [输入参数] */ private function ParamsCheck($params = []) { // 请求类型 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'DB_TYPE', 'error_msg' => '请选择数据库类型', ], [ 'checked_type' => 'in', 'key_name' => 'DB_CHARSET', 'checked_data' => array_column($this->charset_type_list, 'charset'), 'error_msg' => '请选择数据编码', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_HOST', 'error_msg' => '请填写数据库服务器地址', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_PORT', 'error_msg' => '请填写数据库端口', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_NAME', 'error_msg' => '请填写数据库名', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_USER', 'error_msg' => '请填写数据库用户名', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_PWD', 'error_msg' => '请填写数据库密码', ], [ 'checked_type' => 'empty', 'key_name' => 'DB_PREFIX', 'error_msg' => '请填写数据表前缀', ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } return DataReturn('success', 0); } } ?>