<?php
// +----------------------------------------------------------------------
// | Description: 安装
// +----------------------------------------------------------------------
// | Author:  Michael_xu | gengxiaoxu@5kcrm.com 
// +----------------------------------------------------------------------

namespace app\admin\controller;

use think\Controller;
use think\Exception;
use think\Request;
use think\Db;
use Env;

class Install extends Controller
{
    // private $count = 100;
    // private $now = 0; 

    public function _initialize()
    {
        /*防止跨域*/
        header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
        header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, authKey, sessionId");
        $param = Request::instance()->param();
        $this->param = $param;

//        $request = request();
//        $m = strtolower($request->module());
//        $c = strtolower($request->controller());
//        $a = strtolower($request->action());
//
//        if (!in_array($a, array('upgrade','upgradeprocess','checkversion')) && file_exists(CONF_PATH . "install.lock")) {
//            echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
//            die();
//        }
    }

    private $upgrade_site = "http://message.72crm.com/";

    /**
     * [index 安装步骤]
     * @author Michael_xu
     * @param
     */
    public function index()
    {
        $protocol = strpos(strtolower($_SERVER['HTTP_REFERER']), 'https') === false ? 'http' : 'https';

        if (strpos(request()->url(), "index.php") === false) {
            $url =  $protocol. "://" .$_SERVER["HTTP_HOST"] . "/index.php" . request()->url();
            header("Location:" . $url);
        }

        if (file_exists(CONF_PATH . "install.lock")) {
            echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$protocol."://".$_SERVER["HTTP_HOST"]."';</script>";
            die();
        }

        if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
            echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('缺少必要的数据库文件!');location.href='".$protocol."://".$_SERVER["HTTP_HOST"]."';</script>";
            die();
        }

        return $this->fetch('index');
    }

    public function step1()
    {
        if (strpos(request()->url(), "index.php") === false) {
            $protocol = strpos(strtolower($_SERVER['HTTP_REFERER']), 'https') === false ? 'http' : 'https';
            $url =  $protocol. "://" .$_SERVER["HTTP_HOST"] . "/index.php" . request()->url();
            header("Location:" . $url);
        }

		session('install_error',null);
        $data           = [];
        $data['env']    = self::checkNnv();
        $data['dir']    = self::checkDir();
        $data['version'] = $this->version();
        $this->assign('data',$data);
        return $this->fetch('step1');
    }

    //版本
    public function version()
    {
        $res = include(CONF_PATH.'version.php');
        return $res ? : array('VERSION' => '11.0.0','RELEASE' => '20210219');
    }

    public function step2(){
		if (session('install_error')){
            echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('环境检测未通过,不能进行下一步操作!');location.href='".$_SERVER["HTTP_REFERER"]."';</script>";
            die();
        }
        if (strpos(request()->url(), "index.php") === false) {
            $protocol = strpos(strtolower($_SERVER['HTTP_REFERER']), 'https') === false ? 'http' : 'https';
            $url =  $protocol. "://" .$_SERVER["HTTP_HOST"] . "/index.php" . request()->url();
            header("Location:" . $url);
        }
        $data['os'] = PHP_OS;
        $data['php'] = phpversion();
        $data['version'] = $this->version();
        $this->assign('envir_data',$data);
        return $this->fetch();
    }

    public function step3(){
        return $this->fetch();
    }

    public function step4(){
        if (session('install_error')){
            return resultArray(['error' => '环境检测未通过,不能进行下一步操作!']);
        }
        if (file_exists(CONF_PATH . "install.lock")) {
            return resultArray(['error' => '请勿重复安装!']);
        }
        if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
            return resultArray(['error' => '缺少必要的数据库文件!']);
        }
        $temp = $this->param;
        $param = $temp['form'];
        $db_config['type'] = 'mysql';
        $db_config['hostname'] = $param['databaseUrl'];
        $db_config['hostport'] = $param['databasePort'];
        $db_config['database'] = $param['databaseName'];
        $db_config['username'] = $param['databaseUser'];
        $db_config['password'] = $param['databasePwd'];
        $db_config['prefix'] = '5kcrm_';
//        $db_config['prefix'] = $param['databaseTable'];

        $username = $param['root'];
        $password = $param['pwd'];
        $wkcode = $param['wkcode'];
        if (empty($db_config['hostname'])) {
            return resultArray(['error' => '请填写数据库主机!']);
        }
        if (empty($db_config['hostport'])) {
            return resultArray(['error' => '请填写数据库端口!']);
        }
        if (preg_match('/[^0-9]/', $db_config['hostport'])) {
            return resultArray(['error' => '数据库端口只能是数字!']);
        }
        if (empty($db_config['database'])) {
            return resultArray(['error' => '请填写数据库名!']);
        }
        if (empty($db_config['username'])) {
            return resultArray(['error' => '请填写数据库用户名!']);
        }
        if (empty($db_config['password'])) {
            return resultArray(['error' => '请填写数据库密码!']);
        }
        if (empty($db_config['prefix'])) {
            return resultArray(['error' => '请填写表前缀!']);
        }
        if (preg_match('/[^a-z0-9_]/i', $db_config['prefix'])) {
            return resultArray(['error' => '表前缀只能包含数字、字母和下划线!']);
        }
        if (empty($username)) {
            return resultArray(['error' => '请填写管理员用户名!']);
        }
        if (empty($wkcode)) {
            return resultArray(['error' => '请填写序列号!']);
        }
        $resCheckData = checkWkCode($wkcode);
        if (!$resCheckData) {
            return resultArray(['error' => '序列号错误!']);
        }
//        $resData = object_to_array(json_decode($resCheckData));
//        if ($resData['date'] != date('Y-m-d')) {
//            return resultArray(['error' => '序列号已失效,请前往悟空官网个人中心获取最新数据!']);
//        }
        if (empty($password)) {
            return resultArray(['error' => '请填写管理员密码!']);
        }
        session('install_count','');
        session('install_now','');
        $database = $db_config['database'];
		unset($db_config['database']);
        $connect = Db::connect($db_config);
        // 检测数据库连接
        try{
            $ret = $connect->execute('select version()');
        }catch(\Exception $e){
            return resultArray(['error' => '数据库连接失败,请检查数据库配置4!']);
        }
        $check = $connect->execute("SELECT * FROM information_schema.schemata WHERE schema_name='".$database."'");
        if (!$check && !$connect->execute("CREATE DATABASE IF NOT EXISTS `".$database."` default collate utf8_general_ci ")) {
            return resultArray(['error' => '没有找到您填写的数据库名且无法创建!请检查连接账号是否有创建数据库的权限!']);
        }
		$db_config['database'] = $database;
        self::mkDatabase($db_config);
        self::mkLicense($wkcode);
        $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
        $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm1.sql');
        $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
        if ($sqlList) {
            $sqlList = array_filter($sqlList);
            $install_count = count($sqlList);
            session('install_count',$install_count);
            foreach ($sqlList as $k=>$v) {
                $install_now = $k+1;
                session('install_now',$install_now);
                try {
                    $temp_sql = $v.';';
                    Db::connect($db_config)->query($temp_sql);
                } catch(\Exception $e) {
                    // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                    return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                }
            }
        }
//        $salt = substr(md5(time()),0,4);
//        $password = user_md5(trim($password), $salt, $username);
//		//插入信息
//        Db::connect($db_config)->query("insert into ".$db_config['prefix']."admin_user (username, password, salt, img, thumb_img, realname, create_time, num, email, mobile, sex, status, structure_id, post, parent_id, type, authkey, authkey_time ) values ( '".$username."', '".$password."', '".$salt."', '', '', '管理员', ".time().", '', '', '".$username."', '', 1, 1, 'CEO', 0, 1, '', 0 )");
//        Db::connect($db_config)->query("insert into ".$db_config['prefix']."hrm_user_det (user_id, join_time, type, status, userstatus, create_time, update_time, mobile, sex, age, job_num, idtype, idnum, birth_time, nation, internship, done_time, parroll_id, email, political, location, leave_time ) values ( 1, ".time().", 1, 1, 2, ".time().", ".time().", '".$username."', '', 0, '', 0, '', '', 0, 0, 0, 0, '', '', '', 0 )");
//        touch(CONF_PATH . "install.lock");
        return resultArray(['data'=>'安装成功']);
    }
    public function step7(){
        $temp = $this->param;
        $param = $temp['form'];
        $db_config['type'] = 'mysql';
        $db_config['hostname'] = $param['databaseUrl'];
        $db_config['hostport'] = $param['databasePort'];
        $db_config['database'] = $param['databaseName'];
        $db_config['username'] = $param['databaseUser'];
        $db_config['password'] = $param['databasePwd'];
        $db_config['prefix'] = '5kcrm_';
        $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
        $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm2.sql');
        $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
        if ($sqlList) {
            $sqlList = array_filter($sqlList);
            $install_count = count($sqlList);
            session('install_count',$install_count);
            foreach ($sqlList as $k=>$v) {
                $install_now = $k+1;
                session('install_now',$install_now);
                try {
                    $temp_sql = $v.';';
                    Db::connect($db_config)->query($temp_sql);
                } catch(\Exception $e) {
                    // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                    return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                }
            }
        }
    return resultArray(['data'=>'安装成功']);
    }

    public function step8(){
        $temp = $this->param;
        $param = $temp['form'];
        $db_config['type'] = 'mysql';
        $db_config['hostname'] = $param['databaseUrl'];
        $db_config['hostport'] = $param['databasePort'];
        $db_config['database'] = $param['databaseName'];
        $db_config['username'] = $param['databaseUser'];
        $db_config['password'] = $param['databasePwd'];
        $db_config['prefix'] = '5kcrm_';
        $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
        $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm3.sql');
        $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
        if ($sqlList) {
            $sqlList = array_filter($sqlList);
            $install_count = count($sqlList);
            session('install_count',$install_count);
            foreach ($sqlList as $k=>$v) {
                $install_now = $k+1;
                session('install_now',$install_now);
                try {
                    $temp_sql = $v.';';
                    Db::connect($db_config)->query($temp_sql);
                } catch(\Exception $e) {
                    // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                    return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                }
            }
        }
        $username = $param['root'];
        $password = $param['pwd'];
        $salt = substr(md5(time()),0,4);
        $password = user_md5(trim($password), $salt, $username);
//		//插入信息
        Db::connect($db_config)->query("insert into ".$db_config['prefix']."admin_user (username, password, salt, img, thumb_img, realname, create_time, num, email, mobile, sex, status, structure_id, post, parent_id, type, authkey, authkey_time ) values ( '".$username."', '".$password."', '".$salt."', '', '', '管理员', ".time().", '', '', '".$username."', '', 1, 1, 'CEO', 0, 1, '', 0 )");
        Db::connect($db_config)->query("insert into ".$db_config['prefix']."hrm_user_det (user_id, join_time, type, status, userstatus, create_time, update_time, mobile, sex, age, job_num, idtype, idnum, birth_time, nation, internship, done_time, parroll_id, email, political, location, leave_time ) values ( 1, ".time().", 1, 1, 2, ".time().", ".time().", '".$username."', '', 0, '', 0, '', '', 0, 0, 0, 0, '', '', '', 0 )");
        touch(CONF_PATH . "install.lock");
        return resultArray(['data'=>'安装成功']);
    }

    public function step10(){
        $temp = $this->param;
        $param = $temp['form'];
        $db_config['type'] = 'mysql';
        $db_config['hostname'] = $param['databaseUrl'];
        $db_config['hostport'] = $param['databasePort'];
        $db_config['database'] = $param['databaseName'];
        $db_config['username'] = $param['databaseUser'];
        $db_config['password'] = $param['databasePwd'];
        $db_config['prefix'] = '5kcrm_';
        $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
        $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm4.sql');
        $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
        if ($sqlList) {
            $sqlList = array_filter($sqlList);
            $install_count = count($sqlList);
            session('install_count',$install_count);
            foreach ($sqlList as $k=>$v) {
                $install_now = $k+1;
                session('install_now',$install_now);
                try {
                    $temp_sql = $v.';';
                    Db::connect($db_config)->query($temp_sql);
                } catch(\Exception $e) {
                    // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                    return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                }
            }
        }
        return resultArray(['data'=>'安装成功']);
    }

    public function step11(){
        $temp = $this->param;
        $param = $temp['form'];
        $db_config['type'] = 'mysql';
        $db_config['hostname'] = $param['databaseUrl'];
        $db_config['hostport'] = $param['databasePort'];
        $db_config['database'] = $param['databaseName'];
        $db_config['username'] = $param['databaseUser'];
        $db_config['password'] = $param['databasePwd'];
        $db_config['prefix'] = '5kcrm_';
        $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
        $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm5.sql');

        $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
        if ($sqlList) {
            $sqlList = array_filter($sqlList);
            $install_count = count($sqlList);
            session('install_count',$install_count);
            foreach ($sqlList as $k=>$v) {
                $install_now = $k+1;
                session('install_now',$install_now);
                try {
                    $temp_sql = $v.';';
                    Db::connect($db_config)->query($temp_sql);
                } catch(\Exception $e) {
                    // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                    return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                }
            }
        }

        return resultArray(['data'=>'安装成功']);
    }

    /**
     * sql多文件执行
     * @param $sqlList
     * @param $db_config
     * @return \think\response\Json
     */
    public function sqlData($sqlList,$db_config){
        try {
            $install_count = count($sqlList);
            session('install_count',$install_count);
            $res_count=ceil($install_count);
            for($i=0;$i<=$res_count;$i++){
                $page = $i>0?$i*100+1 :1;
                $excelData = array_slice($sqlList, $page ,100);
                if($excelData){
                    foreach($excelData as $k=>$v){
                        $install_now = $k+1;
                        session('install_now',$install_now);
                            $temp_sql = $v.';';
                            Db::connect($db_config)->query($temp_sql);
                            // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
                            return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
                    }
                }
            }
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            return resultArray(['error'=>$e->getMessage()]);
        }
    }

    /**
     * 安装成功界面
     *
     * @author fnqi
     * @date 2021-03-11
     * @return mixed
     */
    public function step5()
    {
        return $this->fetch();
    }

    /**
     * 安装超时界面
     *
     * @author fanqi
     * @date 2021-03-11
     * @return mixed
     */
    public function step6()
    {
        return $this->fetch();
    }

	//ajax 进度条
    public function progress()
    {
        $data['length'] = session('install_count');
        $data['now'] = session('install_now');
        return resultArray(['data'=>$data]);
    }

    //添加database.php文件
    private function mkDatabase(array $data)
    {
        $code = <<<INFO
<?php
return [
    // 数据库类型
    'type'            => 'mysql',
    // 服务器地址
    'hostname'        => '{$data['hostname']}',
    // 数据库名
    'database'        => '{$data['database']}',
    // 用户名
    'username'        => '{$data['username']}',
    // 密码
    'password'        => '{$data['password']}',
    // 端口
    'hostport'        => '{$data['hostport']}',
    // 连接dsn
    'dsn'             => '',
    // 数据库连接参数
    'params'          => [],
    // 数据库编码默认采用utf8
    'charset'         => 'utf8',
    // 数据库表前缀
    'prefix'          => '{$data['prefix']}',
    // 数据库调试模式
    'debug'           => true,
    // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
    'deploy'          => 0,
    // 数据库读写是否分离 主从式有效
    'rw_separate'     => false,
    // 读写分离后 主服务器数量
    'master_num'      => 1,
    // 指定从服务器序号
    'slave_no'        => '',
    // 自动读取主库数据
    'read_master'     => false,
    // 是否严格检查字段是否存在
    'fields_strict'   => true,
    // 数据集返回类型
    'resultset_type'  => 'array',
];

INFO;
        file_put_contents( CONF_PATH.'database.php', $code);
        // 判断写入是否成功
        $config = include CONF_PATH.'database.php';
        if (empty($config['database']) || $config['database'] != $data['database']) {
            return resultArray(['error' => '[config/database.php]数据库配置写入失败!']);
        }
        return true;
    }

    //检查目录权限
    public function check_dir_iswritable($dir_path){
        $dir_path=str_replace( '\\','/',$dir_path);
        $is_writale=1;
        if (!is_dir($dir_path)) {
            $is_writale=0;
            return $is_writale;
        } else {
            $file_hd=@fopen($dir_path.'/test.txt','w');
            if (!$file_hd) {
                @fclose($file_hd);
                @unlink($dir_path.'/test.txt');
                $is_writale=0;
                return $is_writale;
            }
            $dir_hd = opendir($dir_path);
            while (false !== ($file=readdir($dir_hd))) {
                if ($file != "." && $file != "..") {
                    if (is_file($dir_path.'/'.$file)) {
                        //文件不可写,直接返回 
                        if (!is_writable($dir_path.'/'.$file)) {
                            return 0;
                        }
                    } else {
                        $file_hd2=@fopen($dir_path.'/'.$file.'/test.txt','w');
                        if (!$file_hd2) {
                            @fclose($file_hd2);
                            @unlink($dir_path.'/'.$file.'/test.txt');
                            $is_writale=0;
                            return $is_writale;
                        }
                        //递归 
                        $is_writale=check_dir_iswritable($dir_path.'/'.$file);
                    }
                }
            }
        }
        return $is_writale;
    }

    /**
     * [checkVersion 检查升级]
     * @author Michael_xu
     * @param
     */
    public function checkVersion(){
        $version = Config::load('version');
        $info = sendRequest($this->upgrade_site.'index.php?m=version&a=checkVersion', $version['VERSION']);
        if ($info){
            return resultArray(['data' => $info]);
        } else {
            return resultArray(['error' => '检查新版本出错!']);
        }
    }

    /**
     * 环境检测
     * @return array
     */
    private function checkNnv()
    {
        $items = [
            'os'      => ['操作系统', PHP_OS, '类Unix', 'ok'],
            'php'     => ['PHP版本', PHP_VERSION, '7.3 ( <em style="color: #888; font-size: 12px;">>= 7.0</em> )', 'ok','性能更佳'],
            'gd'      => ['gd', '开启', '开启', 'ok'],
            'openssl' => ['openssl', '开启', '开启', 'ok'],
            'pdo'     => ['pdo', '开启', '开启', 'ok'],
        ];
        // linux系统下需要posix扩展
        if (in_array(PHP_OS, ['Linux', 'centos', 'Centos', 'ubuntu', 'Ubuntu'])) {
            $items['posix'] = ['posix', '开启', '开启', 'ok'];
        }
        session('install_error','');
        if (substr($items['php'][1],0,3) < '7.0') {
            $items['php'][3] = 'error';
            session('install_error', true);
        }

        if (!extension_loaded('gd')) {
            $items['gd'][1] = '未开启';
            $items['gd'][3] = 'error';
            session('install_error', true);
        }

        if (!extension_loaded('openssl')) {
            $items['openssl'][1] = '未开启';
            $items['openssl'][3] = 'error';
            session('install_error', true);
        }
        if (!extension_loaded('pdo')) {
            $items['pdo'][1] = '未开启';
            $items['pdo'][3] = 'error';
            session('install_error', true);
        }
        // linux系统下检查是否加载了posix扩展
        if (in_array(PHP_OS, ['Linux', 'centos', 'Centos', 'ubuntu', 'Ubuntu']) && !extension_loaded('posix')) {
            $items['posix'][1] = '未开启';
            $items['posix'][3] = 'error';
            session('install_error', true);
        }
        return $items;
    }

    /**
     * 目录权限检查
     * @return array
     */
    private function checkDir()
    {
        $items = [
            ['dir', $this->root_path.'application', 'application', '读写', '读写', 'ok'],
            ['dir', $this->root_path.'extend', 'extend', '读写', '读写', 'ok'],
            ['dir', $this->root_path.'runtime', './temp', '读写', '读写', 'ok'],
            ['dir', $this->root_path.'public', './upload', '读写', '读写', 'ok'],
            ['file', $this->root_path.'config', 'config', '读写', '读写', 'ok'],
        ];
        foreach ($items as &$v) {
            if ($v[0] == 'dir') {// 文件夹
                if (!is_writable($v[1])) {
                    if (is_dir($v[1])) {
                        $v[4] = '不可写';
                        $v[5] = 'no';
                    } else {
                        $v[4] = '不存在';
                        $v[5] = 'no';
                    }
                    session('install_error', true);
                }
            } else {// 文件
                if (!is_writable($v[1])) {
                    $v[4] = '不可写';
                    $v[5] = 'no';
                    session('install_error', true);
                }
            }
        }
        return $items;
    }

    /**
     * 验证序列号
     * @param
     * @return
     */
    public function checkCodeOld($username) {
        $encryption = md5($username);
        $substr = substr($username, strlen($username)-6);
        $subArr = str_split($substr, 1);
        $code = '';
        for ($i = 0; $i <= 5; $i++) {
            $code .= $encryption[$subArr[$i]];
        }
        return $code;
    }

    //写入license文件
    private function mkLicense($wkcode)
    {
        file_put_contents( CONF_PATH.'license.dat', $wkcode);
        // 判断写入是否成功
        // $config = include CONF_PATH.'license.dat';
        // if (empty($config)) {
        //     return resultArray(['error' => 'license配置写入失败!']);
        // }
        return true;
    }
}