<?php
# MetInfo Enterprise Content Management System
# Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved.

defined('IN_MET') or exit ('No permission');
load::sys_class('admin');

class install extends admin
{
    public function __construct()
    {
        parent::__construct();
        $this->version = '7.8';
    }

    public function dosql()
    {
        global $_M;
        $this->update_system($this->version);

        //7.8管理员权限更新
        include_once __DIR__ . '/update_78.class.php';
        $update78 = new update_78();
        $update78 ->run();

        //清除缓存
        deldir('upload/thumb_src', 1);
        deldir('cache', 1);

        //用户协议文件
        @unlink(PATH_WEB . 'upload/file/license.html');
    }

    public function update_system($version)
    {
        global $_M;
        //更新版本号
        self::update_ver($version);
        self::updataLogs('update_ver');

        switch (strtolower($_M['config']['db_type'])) {
            case 'mysql':
                //检测新增数据表和字段
                self::diff_fields($version);
                self::updataLogs('diff_fields');
                //更新表字段默认值
                self::alter_table($version);
                self::updataLogs('alter_table');
                break;
            case 'sqlite':
                self::databack_sqlite();
                self::updataLogs('databack_sqlite');
                self::diff_fields_sqlite($version);
                self::updataLogs('diff_fields_sqlite');
                break;
            case 'dmsql':
                break;
        }

        //注册数据表
        self::table_regist();
        self::updataLogs('table_regist');

        //添加配置
        self::add_config();
        self::updataLogs('add_config');

        //配置变更
        self::modify_config();
        self::updataLogs('modify_config');

        //更新语言
        self::update_language($version);
        self::updataLogs('update_language');

        //删除系统冗余文件
        self::del_sys_file();
        self::updataLogs('del_sys_file');
        return;
    }

    /**
     * 升级日志
     * @param string $action
     */
    protected function updataLogs($action = '')
    {
        file_put_contents(PATH_WEB . 'update_logs.log', "{$action}\n", FILE_APPEND);
    }

    /**
     * 更新版本号
     * @param string $version
     */
    public function update_ver($version = '')
    {
        global $_M;
        $query = "UPDATE {$_M['table']['config']} SET value = '{$version}' WHERE name = 'metcms_v'";
        DB::query($query);
        return;
    }

    /**
     * 对比数据库机构
     * @param $version
     */
    public function diff_fields($version)
    {
        global $_M;
        $diffs = self::get_diff_tables();
        if (isset($diffs['table'])) {
            foreach ($diffs['table'] as $table => $detail) {
                $sql = "CREATE TABLE IF NOT EXISTS `{$table}` (";
                foreach ($detail as $k => $v) {
                    if ($k == 'id') {
                        $sql .= "`{$k}` {$v['Type']} {$v['Extra']} ,";
                    } else {
                        $sql .= "`{$k}` {$v['Type']}  ";
                        if ($v['Default'] === null) {
                            $sql .= " DEFAULT NULL ";
                        } else {
                            $sql .= " DEFAULT '{$v['Default']}' ";
                        }
                        $sql .= " {$v['Extra']} ,";
                    }
                }
                $sql .= "PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;";
                DB::query($sql);
                add_table(str_replace($_M['config']['tablepre'], '', $table));
            }
        }

        if (isset($diffs['field'])) {
            foreach ($diffs['field'] as $table => $v) {
                foreach ($v as $field => $f) {
                    $sql = "ALTER TABLE `{$table}` ADD COLUMN `{$field}`  {$f['Type']} ";
                    if ($f['Default'] === null) {
                        $sql .= " DEFAULT NULL ";
                    } else {
                        $sql .= " DEFAULT '{$f['Default']}' ";
                    }

                    DB::query($sql);
                }
            }
        }
    }

    /**
     * 更新表字段默认值
     * @param $version
     */
    public function alter_table()
    {
        global $_M;
        $base = self::get_base_table();
        foreach ($base as $table_name => $table) {
            $table_name_now = str_replace('met_', $_M['config']['tablepre'], $table_name);
            $sql = "ALTER TABLE `{$table_name_now}` ";
            foreach ($table as $key => $field) {
                if ($key == 'id') {
                    continue;
                }

                $sql .= " MODIFY COLUMN `{$field['Field']}` {$field['Type']} ";
                if ($field['Default'] === null) {
                    $sql .= " DEFAULT NULL ";
                } else {
                    $sql .= " DEFAULT '{$field['Default']}' ";
                }
                $sql .= ',';
            }
            $sql = trim($sql, ',') . ';';
            DB::query($sql);
        }
    }

    /**
     * 备份sqlite数据库文件
     */
    public function databack_sqlite()
    {
        global $_M;
        $date = date("YmdHis");
        $new_path = PATH_WEB . "config/{$_M['config']['metcms_v']}_{$date}_" . random(5) . '.db.bak';
        $db_path = PATH_WEB . $_M['config']['db_name'];
        if (file_exists($db_path)) {
            copyfile($db_path, $new_path);
        }
    }

    /**
     * @param $version
     * @return void
     */
    protected function diff_fields_sqlite($version)
    {
        global $_M;
        $diffs = self::get_diff_tables_sqlite();

        if (isset($diffs['table'])) {
            foreach ($diffs['table'] as $table => $detail) {
                $sql = "CREATE TABLE [{$table}] (\n";

                $sql_arr = array();
                foreach ($detail as $field => $info) {
                    $type = self::getFieldTypeSqlite($info['Type']);
                    $_sql = "[{$field}] {$type}";

                    if ($info['Key'] == 'PRI') {//主键字段
                        $_sql .= " NOT NULL PRIMARY KEY AUTOINCREMENT ";
                        $sql_arr[] = $_sql;
                        continue;
                    }

                    if ($info['Default'] === null) {//字段默认值
                        $_sql .= " DEFAULT NULL ";
                    } else {
                        $_sql .= " DEFAULT '{$info['Default']}' ";
                    }
                    $sql_arr[] = $_sql;
                }

                $sql .= implode(",\n", $sql_arr);
                $sql .= "\n);";

                DB::query($sql);
                add_table(str_replace($_M['config']['tablepre'], '', $table));
            }
        }

        if (isset($diffs['field'])) {
            foreach ($diffs['field'] as $table => $detail) {
                foreach ($detail as $field => $info) {
                    $type = self::getFieldTypeSqlite($info['Type']);

                    $sql = "ALTER TABLE {$table} ADD COLUMN [{$field}] {$type};";
                    if ($info['Default'] === null) {
                        $sql .= " DEFAULT NULL ";
                    } else {
                        $sql .= " DEFAULT '{$info['Default']}' ";
                    }
                    $res = DB::query($sql);
                }
            }
        }
        return;
    }

    /**
     * 注册数据表
     */
    public function table_regist()
    {
        global $_M;
        add_table('admin_has_permissions|admin_permissions|admin_roles|admin_menus|admin_logs|admin_table|app_config|app_plugin|applist|column|config|cv|download|feedback|flash|flash_button|flist|ifcolumn|ifcolumn_addfile|ifmember_left|img|infoprompt|job|label|lang|lang_admin|language|link|menu|message|mlist|news|online|otherinfo|para|parameter|plist|product|relation|skin_table|tags|templates|ui_config|ui_list|user|user_group|user_group_pay|user_list|user_other|weixin_reply_log|files|history');

    }

    /**
     * 新增系统配置
     */
    public function add_config()
    {
        global $_M;
        $lang_arr = array_keys($_M['langlist']['web']);
        foreach ($lang_arr as $lang) {
            //seo
            //self::_insert_config('met_ccc', '0', 0, $lang);
        }

        //global
        //self::_update_config('met_copyright_type', '0', 0, 'metinfo');
    }

    /**
     * 更新系统配置
     */
    public function modify_config()
    {
        global $_M;
        return;
        //self::_update_config('met_copyright_type', '0', 0, 'metinfo');
    }

    /**
     * 更新语言
     */
    public function update_language($version)
    {
        self::update_admin_lang($version);
        self::update_web_lang($version);
    }

    /**
     * 更新后台语言
     * @param $version
     */
    public function update_admin_lang($version)
    {
        global $_M;
        //添加管理员语言
        $query = "SELECT * FROM {$_M['table']['lang_admin']} WHERE lang = 'cn' AND mark = 'cn'";
        $res = DB::get_one($query);
        if (!$res) {
            $query = "INSERT INTO {$_M['table']['lang_admin']} SET 
                        `name` = '简体中文', 
                        `useok` = 1, 
                        `no_order` = 1, 
                        `mark` = 'cn', 
                        `synchronous` = 'cn',  
                        `link` = '', 
                        `lang` = 'cn' ";
            DB::query($query);
        }

        //后台语言指纹
        $path_cn = PATH_WEB . "app/system/update/include/class/v{$version}lang_admin_cn.json";
        $path_en = PATH_WEB . "app/system/update/include/class/v{$version}lang_admin_en.json";

        $sql = "SELECT * FROM {$_M['table']['lang_admin']} ";
        $admin_lang_list = DB::get_all($sql);
        foreach ($admin_lang_list as $row) {
            $lang = $row['lang'];
            $lang_jsong_path = $lang != 'en' ? $path_cn : $path_en;
            //获取语言对照文件
            $lang_json = file_get_contents($lang_jsong_path);
            $lang_data = json_decode($lang_json, true);
            if (!is_array($lang_data) || !$lang_data) return;

            if (in_array($lang, array('cn', 'en'))) {//强制更新后台语言
                $sql = "DELETE FROM {$_M['table']['language']} WHERE lang = '{$lang}' AND  site = 1 AND app = 0 ";
                DB::query($sql);
                foreach ($lang_data as $lang_row) {
                    if ($lang_row['site'] == 1) {
                        self::add_language($lang_row);
                    }
                }
            } else {//非中英文
                $query = "SELECT `id`,`name` FROM {$_M['table']['language']} WHERE lang = '{$lang}' AND site = '1'";
                $admin_lang = DB::get_all($query);
                $old_lang_index = array();
                foreach ($admin_lang as $lang_item) {
                    $old_lang_index[] = $lang_item['name'];
                }

                $new_lang_index = array_keys($lang_data);
                $diff_lang_idnex = array_diff($new_lang_index, $old_lang_index);

                foreach ($diff_lang_idnex as $name) {
                    if ($lang_data[$name]['site'] == 1) {
                        self::add_language($lang_data[$name], $lang);
                    }
                }
            }
        }
    }

    /**
     * 更新前台语言
     * @param $version
     */
    public function update_web_lang($version)
    {
        global $_M;
        //前台语言指纹
        $path_cn = PATH_WEB . "app/system/update/include/class/v{$version}lang_web_cn.json";
        $path_en = PATH_WEB . "app/system/update/include/class/v{$version}lang_web_en.json";

        $sql = "SELECT * FROM {$_M['table']['lang']} ";
        $web_lang_list = DB::get_all($sql);
        foreach ($web_lang_list as $row) {
            $lang = $row['lang'];
            $lang_jsong_path = $lang != 'en' ? $path_cn : $path_en;
            //获取语言对照文件
            $lang_json = file_get_contents($lang_jsong_path);
            $lang_data = json_decode($lang_json, true);

            if (is_array($lang_data)) {
                $query = "SELECT `id`,`name` FROM {$_M['table']['language']} WHERE lang = '{$lang}' AND site = '0'";
                $web_lang = DB::get_all($query);

                $old_lang_index = array();
                foreach ($web_lang as $lang_item) {
                    $old_lang_index[] = $lang_item['name'];
                }

                $new_lang_index = array_keys($lang_data);
                $diff_lang_idnex = array_diff($new_lang_index, $old_lang_index);

                foreach ($diff_lang_idnex as $name) {
                    if ($lang_data[$name]['site'] == 0) {
                        self::add_language($lang_data[$name], $lang);
                    }
                }
            }
        }
    }

    /**
     * 删除系统冗余文件
     */
    public function del_sys_file()
    {
        global $_M;
        $list = array(
            PATH_WEB . "app/app/ueditor/php",
            PATH_WEB . "app/static/modules/ueditor/php",
            PATH_WEB . "public/plugins/ueditor/php",
        );

        foreach ($list as $row) {
            if (is_dir($row)) {
                deldir($row);
            }
        }
    }

    /*****************************工具方法******************************/
    /**
     * 获取标准数据库文件
     * @return mixed
     */
    public function get_base_table()
    {
        global $_M;
        //$json_sql = "https://www.metinfo.cn/upload/json/v{$this->version}mysql.json";
        $path = PATH_WEB . "app/system/update/include/class/v{$this->version}mysql.json";

        $table_json = file_get_contents($path);
        $base = json_decode($table_json, true);
        return $base;
    }

    /*****************************mysql******************************/
    /**
     * @param $json_sql
     * @return array
     */
    public function get_diff_tables()
    {
        global $_M;
        $tables = self::list_tables();
        $base = self::get_base_table();

        if (!is_array($tables) || !is_array($base)) {
            return;
        }

        $baseTables = array_keys($base);
        $diffTables = array_diff($baseTables, $tables);

        $noTables = array();
        $data = array();
        foreach ($diffTables as $noTable) {
            $table_name = $noTable;
            $noTable = str_replace('met_', $_M['config']['tablepre'], $noTable);
            $data['table'][$noTable] = $base[$table_name];
            $noTables[] = $noTable;
        }

        foreach ($base as $table => $val) {
            if (!in_array($table, $noTables)) {
                $table = str_replace('met_', $_M['config']['tablepre'], $table);
                $fields = self::list_fields($table);
                $diff_field = array_diff_key($val, $fields);
                if ($diff_field) {
                    $data['field'][$table] = $diff_field;
                }
            }
        }
        return $data;
    }

    /**
     * @return array
     */
    public function list_tables()
    {
        global $_M;
        $query = "SHOW TABLE status";
        $tables = array();
        foreach (DB::get_all($query) as $key => $v) {
            $tables[] = str_replace($_M['config']['tablepre'], 'met_', $v['Name']);
        }
        return $tables;
    }

    /**
     * @param $table
     * @return array
     */
    public function list_fields($table)
    {
        global $_M;
        $query = "SHOW FULL FIELDS FROM {$table}";
        $fields = DB::get_all($query);
        $data = array();
        foreach ($fields as $key => $v) {
            $data[$v['Field']] = $v;
        }
        return $data;
    }

    /*****************************sqlite******************************/
    /**
     * sqlite字段对比
     */
    protected function get_diff_tables_sqlite()
    {
        global $_M;
        //标准数据表
        $base = self::get_base_table();
        //当前数据表
        $sql = "select name from sqlite_master where type='table' AND name LIKE '{$_M['config']['tablepre']}%'order by name;";
        $res = DB::get_all($sql);
        $tables = array();
        foreach ($res as $key => $v) {
            $tables[] = str_replace($_M['config']['tablepre'], 'met_', $v['name']);
        }
        if (!is_array($tables) || !is_array($base)) return;

        $sissing_tables = array();
        $sissing_fields = array();

        //数据表检测
        $baseTables = array_keys($base);
        $diffTables = array_diff($baseTables, $tables);
        $noTables = array();
        foreach ($diffTables as $table) {
            $noTables[] = $table;
            $table_name = str_replace('met_', $_M['config']['tablepre'], $table);
            $sissing_tables[$table_name] = $base[$table];
        }

        //表字段检测
        foreach ($base as $table => $val) {
            if (in_array($table, $noTables)) {//表不存在无需检测字段
                continue;
            }

            $table_name = str_replace('met_', $_M['config']['tablepre'], $table);
            $fields = array();
            $sql = "PRAGMA table_info([{$table_name}]);";
            $res = DB::get_all($sql);
            foreach ($res as $key => $v) {
                $fields[$v['name']] = $v;
            }

            $diff_field = array_diff_key($val, $fields);
            if ($diff_field) {
                $sissing_fields[$table_name] = $diff_field;
            }
        }

        $data['table'] = $sissing_tables;
        $data['field'] = $sissing_fields;
        return $data;
    }

    /**
     * sqlite字段映射
     * @param string $type
     * @return mixed|string
     */
    protected function getFieldTypeSqlite($type = '')
    {
        $expr = array(
            '/INT(\([0-9]+\))/i' => 'integer',
            '/varchar\((\d+)\)/i' => 'text($1)',
            '/unsigned/i' => '',
        );

        foreach ($expr as $pattern => $value) {
            $type = preg_replace_callback($pattern, function ($match) use ($value) {
                return str_replace('$1', $match[1], $value);
            }, $type);
        }
        return $type;
    }

    /**
     * 获取sql
     * @param $data
     * @return string
     */
    public function _get_sql($data)
    {
        global $_M;
        $sql = "";
        foreach ($data as $key => $value) {
            if (strstr($value, "'")) {
                $value = str_replace("'", "\'", $value);
            }
            $sql .= " {$key} = '{$value}',";
        }
        return trim($sql, ',');
    }


    /**
     * 新增配置
     * @param string $name
     * @param string $value
     * @param string $cid
     * @param string $lang
     */
    public function _insert_config($name = '', $value = '', $cid = '', $lang = '')
    {
        global $_M;
        $query = "SELECT id FROM {$_M['table']['config']} WHERE  name='{$name}' AND lang = '{$lang}'";
        $config = DB::get_one($query);
        if (!$config) {
            $query = "INSERT INTO {$_M['table']['config']} (name,value,mobile_value,columnid,flashid,lang)VALUES ('{$name}', '{$value}', '', '{$cid}', '0', '{$lang}')";
            DB::query($query);
        }
    }

    /**
     * 更新配置
     * @param string $name
     * @param string $value
     * @param string $cid
     * @param string $lang
     */
    public function _update_config($name = '', $value = '', $cid = '', $lang = '')
    {
        global $_M;
        $query = "SELECT id FROM {$_M['table']['config']} WHERE  name='{$name}' AND lang = '{$lang}'";
        $config = DB::get_one($query);
        if (!$config) {
            $query = "INSERT INTO {$_M['table']['config']} (name,value,mobile_value,columnid,flashid,lang)VALUES ('{$name}', '{$value}', '', '{$cid}', '0', '{$lang}')";
            DB::query($query);
        } else {
            $query = "UPDATE {$_M['table']['config']} SET name = '{$name}',value = '{$value}', columnid = '{$cid}' ,lang = '{$lang}' WHERE id = '{$config['id']}'";
            DB::query($query);
        }
    }

    /**
     * 更新 插入语言
     * @param array $lang_data
     */
    public function add_language($lang_data = array(),$lang = null)
    {
        global $_M;
        $name = $lang_data['name'];
        $value = $lang_data['value'];
        $site = $lang_data['site'];
        $lang_set = $lang ? $lang : $lang_data['lang'];
        $js = $lang_data['array'] ? 1 : 0;
        $app = $lang_data['app'];

        if ($name) {
            $query = "INSERT INTO {$_M['table']['language']} SET name = '{$name}',value='{$value}',site = '{$site}',no_order = 0,array='{$js}', app = '{$app}', lang='{$lang_set}'";
            DB::query($query);
        }
        return;
    }

    /**
     * 获取三级栏目信息
     */
    public function getClass123($cid = '', $lang = '')
    {
        global $_M;
        $classnow = self::getClassById($cid, $lang);

        $return = array();
        if ($classnow) {
            if ($classnow['classtype'] == 1) {
                $return['class1'] = $classnow;
                $return['class2'] = array();
                $return['class3'] = array();
            }

            if ($classnow['classtype'] == 2) {
                $return['class1'] = self::getClassById($classnow['bigclass'], $lang);
                $return['class2'] = $classnow;
                $return['class3'] = array();
            }

            if ($classnow['classtype'] == 3) {
                $bigclass = self::getClassById($classnow['bigclass'], $lang);
                $return['class1'] = self::getClassById($bigclass['bigclass'], $lang);
                $return['class2'] = $bigclass;
                $return['class3'] = $classnow;
            }
            return $return;
        }
        return false;
    }

    /**
     * 获取特定栏目信息
     * @param string $cid
     * @param string $lang
     * @return array|bool
     */
    public function getClassById($cid = '', $lang = '')
    {
        global $_M;
        if ($cid && $lang) {
            $query = "SELECT * FROM {$_M['table']['column']} WHERE lang = '{$lang}' AND id = '{$cid}'";
            $class = DB::get_one($query);
            return $class;
        }
        return false;
    }

    /**
     * 获取栏目配置
     * @param $class_id
     * @return array
     */
    public function getClassConfig($class_id = '')
    {
        global $_M;
        $query = "SELECT * FROM {$_M['table']['config']} WHERE columnid = '{$class_id}'";
        $config_list = DB::get_all($query);
        $list = array();
        foreach ($config_list as $key => $val) {
            $list[$val['name']] = $val['value'];
        }
        return $list;
    }

    /**
     * CURL
     */
    protected function curl($url = '', $data = array(), $timeout = 30)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 0);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    //不要删除该方法
    public function check($pid = '')
    {
    }
}