123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- <?php
- // +----------------------------------------------------------------------
- // | A3Mall
- // +----------------------------------------------------------------------
- // | Copyright (c) 2020 http://www.a3-mall.com All rights reserved.
- // +----------------------------------------------------------------------
- // | Author: xzncit <158373108@qq.com>
- // +----------------------------------------------------------------------
- namespace app\install\controller;
- use app\BaseController;
- use app\install\validate\Database;
- use mall\utils\Tool;
- use think\facade\Cache;
- use think\facade\Db;
- use think\facade\Request;
- use think\facade\Session;
- use think\facade\View;
- class Index extends BaseController {
- protected $path = '';
- protected function initialize(){
- $this->path = dirname(dirname(__FILE__)) . '/data';
- if (file_exists( $this->path.'/install.lock')) {
- exit('程序已安装,如果需要重新安装,请删除 install 模块下 data 目录下的 install.lock 文件');
- }
- }
- public function index(){
- //Session::set("step",1);
- return View::fetch();
- }
- public function check(){
- Session::set("step",2);
- Session::set("error",false);
- // 环境检测
- $env = $this->check_env();
- // 目录文件读写检测
- $dirFile = $this->check_dirfile();
- // 函数检测
- $func = $this->check_func();
- return View::fetch("",[
- "env"=>$env,
- "dirFile"=>$dirFile,
- "func"=>$func,
- "isNext"=>false == Session::get('error')
- ]);
- }
- public function config(){
- if(Request::isAjax()){
- $data = Request::param();
- try {
- validate(Database::class)->check($data);
- }catch (\Exception $ex){
- return json(["status"=>0,"msg"=>$ex->getMessage()]);
- }
- // 缓存配置数据
- $data['type'] = 'mysql';
- Session::set('installData', $data);
- try {
- $mysqli = mysqli_connect(
- $data['hostname'],
- $data['username'],
- $data['password']
- );
- if(!$mysqli){
- throw new \Exception("连接数据库失败,请检查配置是否正确。");
- }
- // 检测数据库连接并检测版本
- $r = mysqli_query($mysqli,'select version() as version limit 1;');
- $version = mysqli_fetch_assoc($r);
- if (version_compare($version['version'], '5.5.3', '<')) {
- throw new \Exception('数据库版本过低,必须 5.5.3 及以上');
- }
- // 检测是否已存在数据库
- $sql = 'SELECT count(*) as count FROM information_schema.schemata WHERE schema_name="'.$data['database'].'"';
- $result = mysqli_query($mysqli,$sql);
- $row = mysqli_fetch_assoc($result);
- if ($row["count"] <= 0) {
- // 创建数据库
- $sql = "CREATE DATABASE IF NOT EXISTS `{$data['database']}` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;";
- if (!mysqli_query($mysqli,$sql)) {
- throw new \Exception("新建数据库失败,请手动建立数据库。");
- }
- }
- mysqli_close($mysqli);
- } catch (\Exception $e) {
- return json(["status"=>0,"msg"=>$e->getMessage()]);
- }
- // 准备工作完成
- return json(["status"=>1,"msg"=>"ok","url"=>str_replace('/install/','/',createUrl('index/install'))]);
- }
- if (Session::get('step') != 2) {
- $this->redirect("check");
- }
- Cache::clear();
- Session::set("step",3);
- return View::fetch();
- }
- public function install(){
- if(Request::isAjax()){
- // 数据准备
- $data = Session::get('installData');
- $type = Request::param('type');
- $result = ['code' => 1, "data"=>['type' => $type]];
- if (!$type) {
- $result['data']['type'] = 'database';
- $result['data']['status'] = 1;
- $result['msg'] = '开始安装数据库表';
- $result['url'] = str_replace('/install/','/',createUrl('index/install'));
- return json($result);
- }
- // 连接数据库
- $db = null;
- if (in_array($type, ['database', 'config'])) {
- try {
- $db = mysqli_connect($data['hostname'],$data['username'],$data['password'],$data['database'],$data['hostport']);
- } catch (\Exception $e) {
- $result['code'] = 0;
- $result['msg'] = $e->getMessage();
- return json($result);
- }
- $db->set_charset('utf8mb4');
- }
- if ('database' == $type) {
- $database = Cache::remember('database', function () {
- $data = Session::get('installData');
- $sql = file_get_contents($this->path . '/a3mall' . ($data['is_demo'] == 1 ? '_demo' : '') . '.sql');
- //$sql = str_replace("`mall_","`".$data["prefix"],$sql);
- $sql = str_replace("\r", "\n", $sql);
- $sql = explode(";\n", $sql);
- Cache::tag('install', 'database');
- return $sql;
- });
- // 数据库表安装完成
- $msg = '';
- $idx = Request::param('idx','0','intval');
- if ($idx >= count($database)) {
- $result['data']['type'] = 'config';
- $result['data']['status'] = 1;
- $result['msg'] = '开始安装配置文件';
- $result['url'] = str_replace('/install/','/',createUrl('index/install'));
- return json($result);
- }
- // 插入数据库表
- if (array_key_exists($idx, $database)) {
- $sql = $value = trim($database[$idx]);
- if (!empty($value)) {
- try {
- if (false !== mysqli_query($db,$sql)) {
- $msg = $this->get_sql_message($sql);
- } else {
- throw new \Exception(mysqli_error($db));
- }
- } catch (\Exception $e) {
- $result['code'] = 0;
- $result['msg'] = $e->getMessage();
- return json($result);
- }
- }
- }
- // 返回下一步
- $result['data']['status'] = 1;
- $result['msg'] = $msg;
- $result['url'] = str_replace('/install/','/',createUrl('index/install',['idx'=>$idx+1]));
- return json($result);
- }
- // 安装配置文件
- if ('config' == $type) {
- // 创建数据库配置文件
- $domain = trim(Request::domain(),"/") . "/";
- $string = <<<EOF
- APP_DEBUG = false
- [APP]
- DEFAULT_TIMEZONE = Asia/Shanghai
- [DATABASE]
- TYPE = mysql
- HOSTNAME = {$data['hostname']}
- DATABASE = {$data['database']}
- PREFIX = {$data['prefix']}
- USERNAME = {$data['username']}
- PASSWORD = {$data['password']}
- HOSTPORT = {$data['hostport']}
- CHARSET = utf8mb4
- DEBUG = false
- [LANG]
- default_lang = zh-cn
- [WEB]
- app_web_url = {$domain}
- [JWT]
- ENCRYPTION = {$this->getRandString(35)}
- SIGN = {$this->getRandString(10)}
- EOF;
- if (!file_put_contents(Tool::getRootPath() . '.env', $string)) {
- $result['code'] = 0;
- $result['msg'] = "数据库配置文件写入失败。";
- return json($result);
- }
- // 创建超级管理员
- $adminData = [
- 'id' => 1,
- 'role_id' => 1,
- 'username' => $data["admin_user"],
- 'password' => md5($data['admin_password']),
- 'lock' => 1,
- 'status' => 0,
- 'count' => 1,
- 'time' => time()
- ];
- try {
- $u = mysqli_query($db,"select * from {$data['prefix']}system_users where id=1");
- $users = mysqli_fetch_assoc($u);
- if(!empty($users)){
- $sql = "UPDATE `{$data['prefix']}system_users` SET ";
- unset($adminData['id']);
- foreach($adminData as $k=>$v){
- $sql .= '`'.$k.'` = ' . "'" . $v . "',";
- }
- $sql = trim($sql,',');
- $sql .= " WHERE `id` = 1;";
- mysqli_query($db,$sql);
- }else{
- $sql = "INSERT INTO `{$data['prefix']}system_users` (".implode(",",array_keys($adminData)).") VALUES (".("'".implode("','",array_values($adminData)) . "'").")";
- mysqli_query($db,$sql);
- }
- } catch (\Exception $e) {
- $result['code'] = 0;
- $result['msg'] = $e->getMessage();
- return json($result);
- }
- $result['data']['status'] = 0;
- $result['msg'] = '安装完成!';
- $result['url'] = str_replace('/install/','/',createUrl('index/complete'));
- return json($result);
- }
- $result['code'] = 0;
- $result['msg'] = "安装出现错误,未完成安装。";
- return json($result);
- }
- if (Session::get('step') != 3) {
- $this->redirect("config");
- }
- Session::set('step', 4);
- return View::fetch();
- }
- public function complete(){
- Cache::clear();
- file_put_contents($this->path . '/install.lock', '');
- return View::fetch("",[
- "data"=>Session::get('installData')
- ]);
- }
- private function check_env(){
- $items = [
- 'os' => ['操作系统', '不限制', '类Unix', PHP_OS, 'check'],
- 'php' => ['PHP版本', '7.1', '7.2+', PHP_VERSION, 'check'],
- 'upload' => ['附件上传', '不限制', '2M+', '未知', 'check'],
- 'gd' => ['GD库', '2.0', '2.0+', '未知', 'check'],
- 'disk' => ['磁盘空间', '100M', '不限制', '未知', 'check'],
- ];
- // PHP环境检测
- if ($items['php'][3] < $items['php'][1]) {
- $items['php'][4] = 'error';
- Session::set('error', true);
- }
- // 附件上传检测
- if (@ini_get('file_uploads'))
- $items['upload'][3] = ini_get('upload_max_filesize');
- // GD库检测
- $tmp = function_exists('gd_info') ? gd_info() : [];
- if (empty($tmp['GD Version'])) {
- $items['gd'][3] = '未安装';
- $items['gd'][4] = 'error';
- Session::set('error', true);
- } else {
- $items['gd'][3] = $tmp['GD Version'];
- }
- unset($tmp);
- // 磁盘空间检测
- if (function_exists('disk_free_space')) {
- $disk_size = floor(disk_free_space(Tool::getRootPath()) / (1024 * 1024));
- $items['disk'][3] = $disk_size . 'M';
- if ($disk_size < 100) {
- $items['disk'][4] = 'error';
- Session::set('error', true);
- }
- }
- return $items;
- }
- private function check_dirfile(){
- $items = [
- ['file', '可写', 'check', '.env'],
- ['dir', '可写', 'check', 'app'],
- ['dir', '可写', 'check', 'runtime'],
- ['dir', '可写', 'check', 'mall'],
- ['dir', '可写', 'check', 'public/static'],
- ['dir', '可写', 'check', 'public/uploads'],
- ];
- foreach ($items as &$val) {
- $item = Tool::getRootPath() . $val[3];
- if ('dir' == $val[0]) {
- if (!is_writable($item)) {
- if (is_dir($item)) {
- $val[1] = '可读';
- $val[2] = 'error';
- Session::set('error', true);
- } else {
- $val[1] = '不存在';
- $val[2] = 'error';
- Session::set('error', true);
- }
- }
- } else {
- if (file_exists($item)) {
- if (!is_writable($item)) {
- $val[1] = '不可写';
- $val[2] = 'error';
- Session::set('error', true);
- }
- } else {
- if (!is_writable(dirname($item))) {
- $val[1] = '不存在';
- $val[2] = 'error';
- Session::set('error', true);
- }
- }
- }
- }
- return $items;
- }
- private function check_func(){
- $items = [
- ['pdo', '支持', 'check', '类'],
- ['pdo_mysql', '支持', 'check', '模块'],
- ['openssl', '支持', 'check', '模块'],
- ['curl', '支持', 'check', '模块'],
- ['bcmath', '支持', 'check', '模块'],
- ['mbstring', '支持', 'check', '模块'],
- ['scandir', '支持', 'check', '函数'],
- ['file_get_contents', '支持', 'check', '函数'],
- ['version_compare', '支持', 'check', '函数'],
- ];
- foreach ($items as &$val) {
- if (('类' == $val[3] && !class_exists($val[0]))
- || ('模块' == $val[3] && !extension_loaded($val[0]))
- || ('函数' == $val[3] && !function_exists($val[0]))
- ) {
- $val[1] = '不支持';
- $val[2] = 'error';
- Session::set('error', true);
- }
- }
- return $items;
- }
- private function get_sql_message($sql){
- if (preg_match('/CREATE TABLE? `([^ ]*)`/is', $sql, $matches)) {
- return !empty($matches[1]) ? "创建数据库表 {$matches[1]} 完成" : '';
- }
- if (preg_match('/INSERT INTO? `([^ ]*)`/is', $sql, $matches)) {
- return !empty($matches[1]) ? "插入数据库行 {$matches[1]} 完成" : '';
- }
- if (preg_match('/ALTER TABLE? `([^ ]*)`/is', $sql, $matches)) {
- if (mb_strpos($sql, 'MODIFY')) {
- return !empty($matches[1]) ? "调整数据库索引 {$matches[1]} 完成" : '';
- } else {
- return !empty($matches[1]) ? "创建数据库索引 {$matches[1]} 完成" : '';
- }
- }
- return '';
- }
- private function getRandString($len=10){
- $string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
- $length = strlen($string)-1;
- $s = '';
- for ($i=0;$i<$len;$i++) {
- $num=mt_rand(0,$length);
- $s .= $string[$num];
- }
- return $s;
- }
- }
|