isAjax()){ $type = input("key", ''); $msg = '缓存更新成功'; switch ($type) { case 'all': // 清除缓存 case 'content': Cache::clear(); if ($type == 'content') { $msg = '数据缓存清除成功'; break; } // 数据表缓存清除 case 'data_table_cache': if (is_dir('runtime/schema')) { rmdirs("schema"); } if ($type == 'data_table_cache') { $msg = '数据表缓存清除成功'; break; } // 模板缓存清除 case 'template_cache': if (is_dir('runtime/temp')) { rmdirs("temp"); } if ($type == 'template_cache') { $msg = '模板缓存清除成功'; break; } } return success(0,$msg,''); }else{ $config_model = new ConfigModel(); $cache_list = $config_model->getCacheList(); $this->assign("cache_list", $cache_list); return $this->fetch('system/cache'); } } /** * 插件管理 */ public function addon() { $addon = new Addon(); if (request()->isAjax()) { $addon_name = input("addon_name"); $tag = input("tag", "install"); if ($tag == 'install') { $res = $addon->install($addon_name); return $res; } else { $res = $addon->uninstall($addon_name); return $res; } } $uninstall = $addon->getUninstallAddonList(); $install = $addon->getAddonList(); $this->assign("addons", $install['data']); $this->assign("uninstall", $uninstall['data']); return $this->fetch('system/addon'); } /** * 数据库管理 */ public function database() { $database = new Database(); $table = $database->getDatabaseList(); $this->assign('list', $table); $this->forthMenu(); return $this->fetch('system/database'); } /** * 数据库还原页面展示 */ public function importlist() { $database = new Database(); $path = $database->backup_path; if (!is_dir($path)) { $mode = intval('0777', 8); mkdir($path, $mode, true); } $flag = \FilesystemIterator::KEY_AS_FILENAME; $glob = new \FilesystemIterator($path, $flag); $list = array(); foreach ($glob as $name => $file) { if (preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)) { $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d'); $date = "{$name[0]}-{$name[1]}-{$name[2]}"; $time = "{$name[3]}:{$name[4]}:{$name[5]}"; $part = $name[6]; if (isset($list["{$date} {$time}"])) { $info = $list["{$date} {$time}"]; $info['part'] = max($info['part'], $part); $info['size'] = $info['size'] + $file->getSize(); $info['size'] = $database->format_bytes($info['size']); } else { $info['part'] = $part; $info['size'] = $file->getSize(); $info['size'] = $database->format_bytes($info['size']); } $info['name'] = date('Ymd-His', strtotime("{$date} {$time}"));; $extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION)); $info['compress'] = ($extension === 'SQL') ? '-' : $extension; $info['time'] = strtotime("{$date} {$time}"); $list[] = $info; } } if (!empty($list)) { $list = $database->my_array_multisort($list, "time"); } $this->assign('list', $list); $this->forthMenu(); return $this->fetch('system/importlist'); } /** * 还原数据库 */ public function importData() { $time = request()->post('time', ''); $part = request()->post('part', 0); $start = request()->post('start', 0); $database = new Database(); if (is_numeric($time) && (is_null($part) || empty($part)) && (is_null($start) || empty($start))) { // 初始化 // 获取备份文件信息 $name = date('Ymd-His', $time) . '-*.sql*'; $path = realpath($database->backup_path) . DIRECTORY_SEPARATOR . $name; $files = glob($path); $list = array(); foreach ($files as $name) { $basename = basename($name); $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d'); $gz = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename); $list[ $match[6] ] = array( $match[6], $name, $gz ); } ksort($list); // 检测文件正确性 $last = end($list); if (count($list) === $last[0]) { session('backup_list', $list); // 缓存备份列表 $return_data = [ 'code' => 1, 'message' => '初始化完成', 'data' => [ 'part' => 1, 'start' => 0 ] ]; return $return_data; } else { $return_data = [ 'code' => -1, 'message' => '备份文件可能已经损坏,请检查!', ]; return $return_data; } } elseif (is_numeric($part) && is_numeric($start)) { $list = session('backup_list'); $db = new dbdatabase($list[ $part ], array( 'path' => realpath($database->backup_path) . DIRECTORY_SEPARATOR, 'compress' => $list[ $part ][2] )); $start = $db->import($start); if ($start === false) { $return_data = [ 'code' => -1, 'message' => '还原数据出错!', ]; return $return_data; } elseif ($start === 0) { // 下一卷 if (isset($list[ ++$part ])) { $data = array( 'part' => $part, 'start' => 0 ); $return_data = [ 'code' => -1, 'message' => "正在还原...#{$part}", 'data' => $data ]; return $return_data; } else { session('backup_list', null); $return_data = [ 'code' => -1, 'message' => "还原完成!", ]; return $return_data; } } else { $data = array( 'part' => $part, 'start' => $start[0] ); if ($start[1]) { $rate = floor(100 * ($start[0] / $start[1])); $return_data = [ 'code' => 1, 'message' => "正在还原...#{$part} ({$rate}%)", ]; return $return_data; } else { $data['gz'] = 1; $return_data = [ 'code' => 1, 'message' => "正在还原...#{$part}", 'data' => $data ]; return $return_data; } } } else { $return_data = [ 'code' => -1, 'message' => "参数有误", ]; return $return_data; } } /** * 数据表修复 */ public function tablerepair() { if (request()->isAjax()) { $table_str = input('tables', ''); $database = new Database(); $res = $database->repair($table_str); return $res; } } /** * 数据表备份 */ public function backup() { $database = new Database(); $tables = input('tables', []); $id = input('id', ''); $start = input('start', ''); if (!empty($tables) && is_array($tables)) { // 初始化 // 读取备份配置 $config = array( 'path' => $database->backup_path . DIRECTORY_SEPARATOR, 'part' => 20971520, 'compress' => 1, 'level' => 9 ); // 检查是否有正在执行的任务 $lock = "{$config['path']}backup.lock"; if (is_file($lock)) { return error(-1, '检测到有一个备份任务正在执行,请稍后再试!'); } else { $mode = intval('0777', 8); if (!file_exists($config['path']) || !is_dir($config['path'])) mkdir($config['path'], $mode, true); // 创建锁文件 file_put_contents($lock, date('Ymd-His', time())); } // 自动创建备份文件夹 // 检查备份目录是否可写 is_writeable($config['path']) || exit('backup_not_exist_success'); session('backup_config', $config); // 生成备份文件信息 $file = array( 'name' => date('Ymd-His', time()), 'part' => 1 ); session('backup_file', $file); // 缓存要备份的表 session('backup_tables', $tables); $dbdatabase = new dbdatabase($file, $config); if (false !== $dbdatabase->create()) { $data = array(); $data['status'] = 1; $data['message'] = '初始化成功'; $data['tables'] = $tables; $data['tab'] = array( 'id' => 0, 'start' => 0 ); return $data; } else { return error(-1, '初始化失败,备份文件创建失败!'); } } elseif (is_numeric($id) && is_numeric($start)) { // 备份数据 $tables = session('backup_tables'); // 备份指定表 $dbdatabase = new dbdatabase(session('backup_file'), session('backup_config')); $start = $dbdatabase->backup($tables[ $id ], $start); if (false === $start) { // 出错 return error(-1, '备份出错!'); } elseif (0 === $start) { // 下一表 if (isset($tables[ ++$id ])) { $tab = array( 'id' => $id, 'table' => $tables[ $id ], 'start' => 0 ); $data = array(); $data['rate'] = 100; $data['status'] = 1; $data['message'] = '备份完成!'; $data['tab'] = $tab; return $data; } else { // 备份完成,清空缓存 unlink($database->backup_path . DIRECTORY_SEPARATOR . 'backup.lock'); session('backup_tables', null); session('backup_file', null); session('backup_config', null); return success(1); } } else { $tab = array( 'id' => $id, 'table' => $tables[ $id ], 'start' => $start[0] ); $rate = floor(100 * ($start[0] / $start[1])); $data = array(); $data['status'] = 1; $data['rate'] = $rate; $data['message'] = "正在备份...({$rate}%)"; $data['tab'] = $tab; return $data; } } else { // 出错 return error(-1, '参数有误!'); } } /** * 删除备份文件 */ public function deleteData() { $name_time = input('time', ''); if ($name_time) { $database = new Database(); $name = date('Ymd-His', $name_time) . '-*.sql*'; $path = realpath($database->backup_path) . DIRECTORY_SEPARATOR . $name; array_map("unlink", glob($path)); if (count(glob($path))) { return error(-1, "备份文件删除失败,请检查权限!"); } else { return success(1, "备份文件删除成功!"); } } else { return error(-1, "参数有误!"); } } public function auth() { $this->forthMenu(); $upgrade_model = new UpgradeModel(); $auth_info = $upgrade_model->authInfo(); $last_version = $upgrade_model->getLatestVersion(); $data = []; //获取当前的版本信息 $auth_version = [ 'B2B2C_STANDARD' => 'B2B2C多商户企业版', ]; if ($auth_info['code'] === '0') { $data = [ 'auth_status' => 1, 'devolution_version' => $auth_version[$auth_info['data']['module_mark']] ?? '--', 'current_version' => defined('SYS_VERSION_NO') ? SYS_VERSION_NO : '--', 'current_version_release' => defined('SYS_RELEASE') ? SYS_RELEASE : '--', 'last_version' => $last_version['data']['version_name'], 'last_version_release' => $last_version['data']['version_release'] ]; $data = array_merge($data, $auth_info['data']); } $this->assign('data', $data); return $this->fetch('system/auth'); } /** * 系统升级 */ public function upgrade() { if (request()->isAjax()) { $upgrade_model = new UpgradeModel(); return $upgrade_model->getUpgradeVersion(); } $this->forthMenu(); return $this->fetch('system/upgrade'); } /** * 版本详情 * @return mixed */ public function version() { $version_release = input('version_release'); if (empty($version_release)) { return $this->error('参数错误', url('admin/system/upgrade')); } $upgrade_model = new UpgradeModel(); $version_info = $upgrade_model->getUpgradeInfo($version_release); if(!empty($version_info["data"])) { $version_info["data"]["error"] = []; try { //判断upload/upgrade可写权限 $upgrade_root = 'upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release']; dir_mkdir($upgrade_root); if(!is_writeable($upgrade_root)){ $version_info["data"]["error"][] = $upgrade_root; } //备份路径 $backup_path = 'upload/backup'; dir_mkdir($backup_path); if(!is_writeable($backup_path)){ $version_info["data"]["error"][] = $backup_path; } //本地要覆盖的文件路径 => mds加密 $two_dev_files = []; //文件重置 foreach ($version_info['data']['files'] as $k => $v) { if(!sp_exist_dir($v)) { $version_info["data"]["error"][] = $v; } else { if(file_exists($v) && !is_writeable($v)){ $version_info["data"]["error"][] = $v; } if(file_exists($v)) { $two_dev_files[$v] = md5(file_get_contents($v)); }else{ $two_dev_files[$v] = ''; } } if(file_exists('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'].'/release/' . $v)) { unset($version_info['data']['files'][$k]); } } $two_dev_files = $upgrade_model->getTowDevFiles($two_dev_files); $version_info['data']['two_dev_files'] = $two_dev_files['data']; if(!empty($version_info['data']['files'])) { sort($version_info['data']['files']); } if(file_exists('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/database.sql')) { unlink('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/database.sql'); } //生成升级sql文件 $dir_make = dir_mkdir('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release']); if($dir_make) { $res = file_put_contents('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/db_upgrade.sql', charset2utf8($version_info['data']['sqls'])); }else{ $version_info["data"]["error"][] = 'upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'].'/db_upgrade.sql'; } $version_info["data"]['script_count'] = count($version_info["data"]['scripts']); $version_info["data"]['file_count'] = count($version_info["data"]['files']); if(!empty($version_info['data']['two_dev_files'])) { $version_info['data']['tow_dev_file_count'] = count($version_info['data']['two_dev_files']); }else{ $version_info['data']['tow_dev_file_count'] = 0; } session("version_update", $version_info['data']);//记录更新文件序列 } catch (Exception $e){ return $this->error($e->getMessage()); } }else{ if($version_info["code"] < 0){ $message = $version_info["message"]; if($version_info["code"] == -100){ $message .= " 服务续费请跳转到官网续费"; } return $this->error($message); } } $current_version = [ 'SYS_RELEASE' => SYS_RELEASE, 'SYS_VERSION_NO' => SYS_VERSION_NO ]; $this->assign('current_verison', $current_version); $this->assign('version_info', $version_info['data']); return $this->fetch('system/version'); } public function versionDownload() { $version_info = session('version_update'); $this->assign('version_info', $version_info); $this->assign("download_path", 'upload/upgrade/' . $version_info['sys_version'] . '/' . $version_info['sys_release'] . '/release/'); return $this->fetch('system/version_download'); } public function versionUpgrade() { $version_info = session('version_update'); $this->assign('version_info', $version_info); return $this->fetch('system/version_upgrade'); } /** * 备份将覆盖的文件 * @return array|\think\response\Json */ public function backupFile() { try{ $session = session("version_update"); if(!empty($session)) { //检测文件完整性 foreach ($session['files'] as $k => $v) { $temp_path = 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/'.$v; if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $temp_path) > 0){ $temp_path = iconv('utf-8','gbk', $temp_path); } if(!file_exists($temp_path)) { return error("", "文件缺失!"); } } dir_mkdir('upload/backup/release'); //文件备份 $this->backOriginalFile('upload/upgrade/'.$session['sys_version'].'/'.$session['sys_release'].'/release', 'upload/upgrade/'.$session['sys_version'].'/'.$session['sys_release'].'/release/','upload/backup/release/'); return json(['code' => 0]); } } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 备份文件 * @param $from_path * @param $replace_path 将替换的 * @param $to_path */ public function backOriginalFile($from_path, $replace_path, $to_path){ try{ //得到原文件的文件结构 //1、首先先读取文件夹 $temp = scandir($from_path); //遍历文件夹 foreach($temp as $v){ $temp = $from_path . '/' . $v; $temp_path = substr_replace($temp,"", strpos($temp,$replace_path), strlen($replace_path)); if(is_dir($temp)) {//如果是文件夹则执行 if($v=='.' || $v=='..'){//判断是否为系统隐藏的文件.和.. 如果是则跳过否则就继续往下走,防止无限循环再这里。 continue; } if(is_dir($temp_path)) { dir_mkdir($to_path.$temp_path); } $this->backOriginalFile($temp, $replace_path, $to_path);//因为是文件夹所以再次调用自己这个函数,把这个文件夹下的文件遍历出来 }else{ if(file_exists($temp_path)){ copy($temp_path,$to_path . $temp_path); } } } } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 备份数据库 * @return mixed[]|string[] */ public function backupSql(){ try{ $database = new Database(); ini_set('memory_limit','500M'); $size = 300; $volumn = 1024 * 1024 * 2; $dump = ''; $last_table = input('last_table', ''); $series = max(1, input('series', 1)); if (empty($last_table)) { $catch = true; } else { $catch = false; } $bakdir = 'upload/backup/sql'; if (!is_dir($bakdir)) { dir_mkdir($bakdir); } $tables = $database->getDatabaseList(); if (empty($tables)) { return json(["code" => 0]); } foreach ($tables as $table) { $table = array_shift( $table); if (!empty($last_table) && $table == $last_table) { $catch = true; } if (!$catch) { continue; } if (!empty($dump)) { $dump .= "\n\n"; } if ($table != $last_table) { $row = $database->getTableSchemas($table); $dump .= $row; } $index = 0; if (!empty(input('index'))) { $index = input('index'); } //枚举所有表的INSERT语句 while (true) { $start = $index * $size; $result = $database->getTableInsertSql($table, $start, $size); if (!empty($result)) { $dump .= $result['data']; if (strlen($dump) > $volumn) { $bakfile = "upload/backup/sql/backup-{$series}.sql"; $dump .= "\n\n"; file_put_contents($bakfile, $dump); ++$series; ++$index; $current = array( 'last_table' => $table, 'index' => $index, 'series' => $series, ); $current_series = $series - 1; return json(['data' => $current, 'code' => 0, 'message' => '正在导出数据, 请不要关闭浏览器, 当前第 ' . $current_series . ' 卷.']); } } if (empty($result) || count($result['result']) < $size) { break; } ++$index; } } $bakfile = "upload/backup/sql/backup-{$series}.sql"; $dump .= "\n\n----MySQL Dump End"; file_put_contents($bakfile, $dump); return json(['code' => 10, 'message' => '数据库备份完成']); } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 下载文件 * @return array|bool|string */ public function download() { if (request()->isAjax()) { try{ $index = input("index", 0); $session = session("version_update"); if(!empty($session)) { $up_model = new UpgradeModel(); $file = isset($session['files'][$index]) ? $session['files'][$index] : ''; if(empty($file)) { return json(['code' => 10, 'message' => 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/']); } $data = array( 'file' => $file, "version_release" => $session["sys_release"], "module_mark" => $session["sys_version"], "token" => $session["token"] ); $info = $up_model->download($data);//异步下载更新文件 //下载文件失败 if(empty($info["data"])) return json($info); $file_path = dirname($file); $info = base64_decode($info['data']); $dir_make = dir_mkdir('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/' . $file_path); if($dir_make) { if(!empty($info)) { $temp_path = 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/' . $file; if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $temp_path) > 0) { $temp_path = iconv('utf-8','gbk',$temp_path); } file_put_contents($temp_path, $info); return json(['code' => 0, 'message' => $file]); } else { return json(['code' => -1, 'message' => '升级文件不存在']); } } else { return json(['code' => -1, 'message' => '文件读写权限不足']); } } else { return json(['code' => -1, 'message' => '当前没有可升级的文件']); } } catch (Exception $e) { return json(['code' => -1, 'message' => $e->getMessage()]); } } } /** * 更新文件覆盖 * @return mixed[]|string[] */ public function executeFile(){ try{ $session = session("version_update"); if(!empty($session)) { //文件替换 dir_copy('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release', './'); return json(['code' => 0]); } } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 更新sql 执行 * @return mixed[]|string[] */ public function executeSql(){ try{ $session = session("version_update"); if(!empty($session)) { //执行数据库 $sql = check_bom('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/db_upgrade.sql'); $sql_arr = parse_sql($sql); // 数据库表前缀 $prefix = config("database")["connections"]["mysql"]["prefix"]; foreach($sql_arr as $k => $v){ $v = trim($v); if(!empty($v) && $v != ""){ $v = str_replace('{{prefix}}', $prefix, $v); Db::execute($v); } } //更新菜单 $menu = new Menu(); $menu->refreshMenu('shop', ''); $menu->refreshMenu('admin', ''); //刷新店铺端权限组 $shop_group_model = new ShopGroupModel(); $shop_group_model->refreshGroup(); return json(['code' => 0]); } } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 更新结束 */ public function upgradeEnd(){ session("version_update", null); //清除缓存 Cache::clear(); return json(['code' => 0]); } /** * 版本恢复 */ public function versionRecovery(){ try{ //回滚备份的文件 if(dir_is_empty('upload/backup/')){ return json(['code' => -1, '没有可会滚得备份!']); } dir_copy('upload/backup/release', './'); //回滚执行的sql语句 $path = "upload/backup/sql"; $flag = \FilesystemIterator::KEY_AS_FILENAME; $glob = new \FilesystemIterator($path, $flag); foreach ($glob as $name => $sql) { $sql_path = $path . '/' . $name; $sql = file_get_contents($sql_path); Db::execute($sql); } return json(['code' => 0, 'message' => '备份回滚成功!']); } catch (Exception $e){ return json(['code' => -1, 'message' => $e->getMessage()]); } } /** * 刷新菜单 测试 */ public function refresh() { $menu = new Menu(); $res = $menu->refreshMenu('admin', ''); var_dump($res); } /** * 刷新自定义模板 测试 */ public function refreshDiy() { $addon = new Addon(); $res = $addon->refreshDiyView(''); var_dump($res); } }