System.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 山西牛酷信息科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com.cn
  8. * 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用。
  9. * 任何企业和个人不允许对程序代码以任何形式任何目的再发布。
  10. * =========================================================
  11. */
  12. namespace app\admin\controller;
  13. use app\model\system\Menu;
  14. use app\model\system\Addon;
  15. use app\model\system\Database;
  16. use app\model\system\Upgrade;
  17. use extend\database\Database as dbdatabase;
  18. use app\model\web\Config as ConfigModel;
  19. use app\model\system\Upgrade as UpgradeModel;
  20. use app\model\shop\ShopGroup as ShopGroupModel;
  21. use think\facade\Cache;
  22. use think\facade\Db;
  23. /**
  24. * 首页 控制器
  25. */
  26. class System extends BaseAdmin
  27. {
  28. /**
  29. * 缓存设置
  30. */
  31. public function cache()
  32. {
  33. if(request()->isAjax()){
  34. $type = input("key", '');
  35. $msg = '缓存更新成功';
  36. switch ($type) {
  37. case 'all':
  38. // 清除缓存
  39. case 'content':
  40. Cache::clear();
  41. if ($type == 'content') {
  42. $msg = '数据缓存清除成功';
  43. break;
  44. }
  45. // 数据表缓存清除
  46. case 'data_table_cache':
  47. if (is_dir('runtime/schema')) {
  48. rmdirs("schema");
  49. }
  50. if ($type == 'data_table_cache') {
  51. $msg = '数据表缓存清除成功';
  52. break;
  53. }
  54. // 模板缓存清除
  55. case 'template_cache':
  56. if (is_dir('runtime/temp')) {
  57. rmdirs("temp");
  58. }
  59. if ($type == 'template_cache') {
  60. $msg = '模板缓存清除成功';
  61. break;
  62. }
  63. }
  64. return success(0,$msg,'');
  65. }else{
  66. $config_model = new ConfigModel();
  67. $cache_list = $config_model->getCacheList();
  68. $this->assign("cache_list", $cache_list);
  69. return $this->fetch('system/cache');
  70. }
  71. }
  72. /**
  73. * 插件管理
  74. */
  75. public function addon()
  76. {
  77. $addon = new Addon();
  78. if (request()->isAjax()) {
  79. $addon_name = input("addon_name");
  80. $tag = input("tag", "install");
  81. if ($tag == 'install') {
  82. $res = $addon->install($addon_name);
  83. return $res;
  84. } else {
  85. $res = $addon->uninstall($addon_name);
  86. return $res;
  87. }
  88. }
  89. $uninstall = $addon->getUninstallAddonList();
  90. $install = $addon->getAddonList();
  91. $this->assign("addons", $install['data']);
  92. $this->assign("uninstall", $uninstall['data']);
  93. return $this->fetch('system/addon');
  94. }
  95. /**
  96. * 数据库管理
  97. */
  98. public function database()
  99. {
  100. $database = new Database();
  101. $table = $database->getDatabaseList();
  102. $this->assign('list', $table);
  103. $this->forthMenu();
  104. return $this->fetch('system/database');
  105. }
  106. /**
  107. * 数据库还原页面展示
  108. */
  109. public function importlist()
  110. {
  111. $database = new Database();
  112. $path = $database->backup_path;
  113. if (!is_dir($path)) {
  114. $mode = intval('0777', 8);
  115. mkdir($path, $mode, true);
  116. }
  117. $flag = \FilesystemIterator::KEY_AS_FILENAME;
  118. $glob = new \FilesystemIterator($path, $flag);
  119. $list = array();
  120. foreach ($glob as $name => $file) {
  121. if (preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)) {
  122. $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
  123. $date = "{$name[0]}-{$name[1]}-{$name[2]}";
  124. $time = "{$name[3]}:{$name[4]}:{$name[5]}";
  125. $part = $name[6];
  126. if (isset($list["{$date} {$time}"])) {
  127. $info = $list["{$date} {$time}"];
  128. $info['part'] = max($info['part'], $part);
  129. $info['size'] = $info['size'] + $file->getSize();
  130. $info['size'] = $database->format_bytes($info['size']);
  131. } else {
  132. $info['part'] = $part;
  133. $info['size'] = $file->getSize();
  134. $info['size'] = $database->format_bytes($info['size']);
  135. }
  136. $info['name'] = date('Ymd-His', strtotime("{$date} {$time}"));;
  137. $extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
  138. $info['compress'] = ($extension === 'SQL') ? '-' : $extension;
  139. $info['time'] = strtotime("{$date} {$time}");
  140. $list[] = $info;
  141. }
  142. }
  143. if (!empty($list)) {
  144. $list = $database->my_array_multisort($list, "time");
  145. }
  146. $this->assign('list', $list);
  147. $this->forthMenu();
  148. return $this->fetch('system/importlist');
  149. }
  150. /**
  151. * 还原数据库
  152. */
  153. public function importData()
  154. {
  155. $time = request()->post('time', '');
  156. $part = request()->post('part', 0);
  157. $start = request()->post('start', 0);
  158. $database = new Database();
  159. if (is_numeric($time) && (is_null($part) || empty($part)) && (is_null($start) || empty($start))) { // 初始化
  160. // 获取备份文件信息
  161. $name = date('Ymd-His', $time) . '-*.sql*';
  162. $path = realpath($database->backup_path) . DIRECTORY_SEPARATOR . $name;
  163. $files = glob($path);
  164. $list = array();
  165. foreach ($files as $name) {
  166. $basename = basename($name);
  167. $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
  168. $gz = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename);
  169. $list[ $match[6] ] = array(
  170. $match[6],
  171. $name,
  172. $gz
  173. );
  174. }
  175. ksort($list);
  176. // 检测文件正确性
  177. $last = end($list);
  178. if (count($list) === $last[0]) {
  179. session('backup_list', $list); // 缓存备份列表
  180. $return_data = [
  181. 'code' => 1,
  182. 'message' => '初始化完成',
  183. 'data' => [ 'part' => 1, 'start' => 0 ]
  184. ];
  185. return $return_data;
  186. } else {
  187. $return_data = [
  188. 'code' => -1,
  189. 'message' => '备份文件可能已经损坏,请检查!',
  190. ];
  191. return $return_data;
  192. }
  193. } elseif (is_numeric($part) && is_numeric($start)) {
  194. $list = session('backup_list');
  195. $db = new dbdatabase($list[ $part ], array(
  196. 'path' => realpath($database->backup_path) . DIRECTORY_SEPARATOR,
  197. 'compress' => $list[ $part ][2]
  198. ));
  199. $start = $db->import($start);
  200. if ($start === false) {
  201. $return_data = [
  202. 'code' => -1,
  203. 'message' => '还原数据出错!',
  204. ];
  205. return $return_data;
  206. } elseif ($start === 0) { // 下一卷
  207. if (isset($list[ ++$part ])) {
  208. $data = array(
  209. 'part' => $part,
  210. 'start' => 0
  211. );
  212. $return_data = [
  213. 'code' => -1,
  214. 'message' => "正在还原...#{$part}",
  215. 'data' => $data
  216. ];
  217. return $return_data;
  218. } else {
  219. session('backup_list', null);
  220. $return_data = [
  221. 'code' => -1,
  222. 'message' => "还原完成!",
  223. ];
  224. return $return_data;
  225. }
  226. } else {
  227. $data = array(
  228. 'part' => $part,
  229. 'start' => $start[0]
  230. );
  231. if ($start[1]) {
  232. $rate = floor(100 * ($start[0] / $start[1]));
  233. $return_data = [
  234. 'code' => 1,
  235. 'message' => "正在还原...#{$part} ({$rate}%)",
  236. ];
  237. return $return_data;
  238. } else {
  239. $data['gz'] = 1;
  240. $return_data = [
  241. 'code' => 1,
  242. 'message' => "正在还原...#{$part}",
  243. 'data' => $data
  244. ];
  245. return $return_data;
  246. }
  247. }
  248. } else {
  249. $return_data = [
  250. 'code' => -1,
  251. 'message' => "参数有误",
  252. ];
  253. return $return_data;
  254. }
  255. }
  256. /**
  257. * 数据表修复
  258. */
  259. public function tablerepair()
  260. {
  261. if (request()->isAjax()) {
  262. $table_str = input('tables', '');
  263. $database = new Database();
  264. $res = $database->repair($table_str);
  265. return $res;
  266. }
  267. }
  268. /**
  269. * 数据表备份
  270. */
  271. public function backup()
  272. {
  273. $database = new Database();
  274. $tables = input('tables', []);
  275. $id = input('id', '');
  276. $start = input('start', '');
  277. if (!empty($tables) && is_array($tables)) { // 初始化
  278. // 读取备份配置
  279. $config = array(
  280. 'path' => $database->backup_path . DIRECTORY_SEPARATOR,
  281. 'part' => 20971520,
  282. 'compress' => 1,
  283. 'level' => 9
  284. );
  285. // 检查是否有正在执行的任务
  286. $lock = "{$config['path']}backup.lock";
  287. if (is_file($lock)) {
  288. return error(-1, '检测到有一个备份任务正在执行,请稍后再试!');
  289. } else {
  290. $mode = intval('0777', 8);
  291. if (!file_exists($config['path']) || !is_dir($config['path']))
  292. mkdir($config['path'], $mode, true); // 创建锁文件
  293. file_put_contents($lock, date('Ymd-His', time()));
  294. }
  295. // 自动创建备份文件夹
  296. // 检查备份目录是否可写
  297. is_writeable($config['path']) || exit('backup_not_exist_success');
  298. session('backup_config', $config);
  299. // 生成备份文件信息
  300. $file = array(
  301. 'name' => date('Ymd-His', time()),
  302. 'part' => 1
  303. );
  304. session('backup_file', $file);
  305. // 缓存要备份的表
  306. session('backup_tables', $tables);
  307. $dbdatabase = new dbdatabase($file, $config);
  308. if (false !== $dbdatabase->create()) {
  309. $data = array();
  310. $data['status'] = 1;
  311. $data['message'] = '初始化成功';
  312. $data['tables'] = $tables;
  313. $data['tab'] = array(
  314. 'id' => 0,
  315. 'start' => 0
  316. );
  317. return $data;
  318. } else {
  319. return error(-1, '初始化失败,备份文件创建失败!');
  320. }
  321. } elseif (is_numeric($id) && is_numeric($start)) { // 备份数据
  322. $tables = session('backup_tables');
  323. // 备份指定表
  324. $dbdatabase = new dbdatabase(session('backup_file'), session('backup_config'));
  325. $start = $dbdatabase->backup($tables[ $id ], $start);
  326. if (false === $start) { // 出错
  327. return error(-1, '备份出错!');
  328. } elseif (0 === $start) { // 下一表
  329. if (isset($tables[ ++$id ])) {
  330. $tab = array(
  331. 'id' => $id,
  332. 'table' => $tables[ $id ],
  333. 'start' => 0
  334. );
  335. $data = array();
  336. $data['rate'] = 100;
  337. $data['status'] = 1;
  338. $data['message'] = '备份完成!';
  339. $data['tab'] = $tab;
  340. return $data;
  341. } else { // 备份完成,清空缓存
  342. unlink($database->backup_path . DIRECTORY_SEPARATOR . 'backup.lock');
  343. session('backup_tables', null);
  344. session('backup_file', null);
  345. session('backup_config', null);
  346. return success(1);
  347. }
  348. } else {
  349. $tab = array(
  350. 'id' => $id,
  351. 'table' => $tables[ $id ],
  352. 'start' => $start[0]
  353. );
  354. $rate = floor(100 * ($start[0] / $start[1]));
  355. $data = array();
  356. $data['status'] = 1;
  357. $data['rate'] = $rate;
  358. $data['message'] = "正在备份...({$rate}%)";
  359. $data['tab'] = $tab;
  360. return $data;
  361. }
  362. } else { // 出错
  363. return error(-1, '参数有误!');
  364. }
  365. }
  366. /**
  367. * 删除备份文件
  368. */
  369. public function deleteData()
  370. {
  371. $name_time = input('time', '');
  372. if ($name_time) {
  373. $database = new Database();
  374. $name = date('Ymd-His', $name_time) . '-*.sql*';
  375. $path = realpath($database->backup_path) . DIRECTORY_SEPARATOR . $name;
  376. array_map("unlink", glob($path));
  377. if (count(glob($path))) {
  378. return error(-1, "备份文件删除失败,请检查权限!");
  379. } else {
  380. return success(1, "备份文件删除成功!");
  381. }
  382. } else {
  383. return error(-1, "参数有误!");
  384. }
  385. }
  386. public function auth()
  387. {
  388. $this->forthMenu();
  389. $upgrade_model = new UpgradeModel();
  390. $auth_info = $upgrade_model->authInfo();
  391. $last_version = $upgrade_model->getLatestVersion();
  392. $data = [];
  393. //获取当前的版本信息
  394. $auth_version = [
  395. 'B2B2C_STANDARD' => 'B2B2C多商户企业版',
  396. ];
  397. if ($auth_info['code'] === '0') {
  398. $data = [
  399. 'auth_status' => 1,
  400. 'devolution_version' => $auth_version[$auth_info['data']['module_mark']] ?? '--',
  401. 'current_version' => defined('SYS_VERSION_NO') ? SYS_VERSION_NO : '--',
  402. 'current_version_release' => defined('SYS_RELEASE') ? SYS_RELEASE : '--',
  403. 'last_version' => $last_version['data']['version_name'],
  404. 'last_version_release' => $last_version['data']['version_release']
  405. ];
  406. $data = array_merge($data, $auth_info['data']);
  407. }
  408. $this->assign('data', $data);
  409. return $this->fetch('system/auth');
  410. }
  411. /**
  412. * 系统升级
  413. */
  414. public function upgrade()
  415. {
  416. if (request()->isAjax()) {
  417. $upgrade_model = new UpgradeModel();
  418. return $upgrade_model->getUpgradeVersion();
  419. }
  420. $this->forthMenu();
  421. return $this->fetch('system/upgrade');
  422. }
  423. /**
  424. * 版本详情
  425. * @return mixed
  426. */
  427. public function version() {
  428. $version_release = input('version_release');
  429. if (empty($version_release)) {
  430. return $this->error('参数错误', url('admin/system/upgrade'));
  431. }
  432. $upgrade_model = new UpgradeModel();
  433. $version_info = $upgrade_model->getUpgradeInfo($version_release);
  434. if(!empty($version_info["data"])) {
  435. $version_info["data"]["error"] = [];
  436. try {
  437. //判断upload/upgrade可写权限
  438. $upgrade_root = 'upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'];
  439. dir_mkdir($upgrade_root);
  440. if(!is_writeable($upgrade_root)){
  441. $version_info["data"]["error"][] = $upgrade_root;
  442. }
  443. //备份路径
  444. $backup_path = 'upload/backup';
  445. dir_mkdir($backup_path);
  446. if(!is_writeable($backup_path)){
  447. $version_info["data"]["error"][] = $backup_path;
  448. }
  449. //本地要覆盖的文件路径 => mds加密
  450. $two_dev_files = [];
  451. //文件重置
  452. foreach ($version_info['data']['files'] as $k => $v) {
  453. if(!sp_exist_dir($v)) {
  454. $version_info["data"]["error"][] = $v;
  455. } else {
  456. if(file_exists($v) && !is_writeable($v)){
  457. $version_info["data"]["error"][] = $v;
  458. }
  459. if(file_exists($v))
  460. {
  461. $two_dev_files[$v] = md5(file_get_contents($v));
  462. }else{
  463. $two_dev_files[$v] = '';
  464. }
  465. }
  466. if(file_exists('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'].'/release/' . $v)) {
  467. unset($version_info['data']['files'][$k]);
  468. }
  469. }
  470. $two_dev_files = $upgrade_model->getTowDevFiles($two_dev_files);
  471. $version_info['data']['two_dev_files'] = $two_dev_files['data'];
  472. if(!empty($version_info['data']['files'])) {
  473. sort($version_info['data']['files']);
  474. }
  475. if(file_exists('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/database.sql')) {
  476. unlink('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/database.sql');
  477. }
  478. //生成升级sql文件
  479. $dir_make = dir_mkdir('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release']);
  480. if($dir_make) {
  481. $res = file_put_contents('upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'] . '/db_upgrade.sql', charset2utf8($version_info['data']['sqls']));
  482. }else{
  483. $version_info["data"]["error"][] = 'upload/upgrade/' . $version_info['data']['sys_version'] . '/' . $version_info['data']['sys_release'].'/db_upgrade.sql';
  484. }
  485. $version_info["data"]['script_count'] = count($version_info["data"]['scripts']);
  486. $version_info["data"]['file_count'] = count($version_info["data"]['files']);
  487. if(!empty($version_info['data']['two_dev_files']))
  488. {
  489. $version_info['data']['tow_dev_file_count'] = count($version_info['data']['two_dev_files']);
  490. }else{
  491. $version_info['data']['tow_dev_file_count'] = 0;
  492. }
  493. session("version_update", $version_info['data']);//记录更新文件序列
  494. } catch (Exception $e){
  495. return $this->error($e->getMessage());
  496. }
  497. }else{
  498. if($version_info["code"] < 0){
  499. $message = $version_info["message"];
  500. if($version_info["code"] == -100){
  501. $message .= " 服务续费请跳转到官网<a href='https://www.niushop.com.cn/member/index.html'>续费</a>";
  502. }
  503. return $this->error($message);
  504. }
  505. }
  506. $current_version = [
  507. 'SYS_RELEASE' => SYS_RELEASE,
  508. 'SYS_VERSION_NO' => SYS_VERSION_NO
  509. ];
  510. $this->assign('current_verison', $current_version);
  511. $this->assign('version_info', $version_info['data']);
  512. return $this->fetch('system/version');
  513. }
  514. public function versionDownload() {
  515. $version_info = session('version_update');
  516. $this->assign('version_info', $version_info);
  517. $this->assign("download_path", 'upload/upgrade/' . $version_info['sys_version'] . '/' . $version_info['sys_release'] . '/release/');
  518. return $this->fetch('system/version_download');
  519. }
  520. public function versionUpgrade() {
  521. $version_info = session('version_update');
  522. $this->assign('version_info', $version_info);
  523. return $this->fetch('system/version_upgrade');
  524. }
  525. /**
  526. * 备份将覆盖的文件
  527. * @return array|\think\response\Json
  528. */
  529. public function backupFile() {
  530. try{
  531. $session = session("version_update");
  532. if(!empty($session)) {
  533. //检测文件完整性
  534. foreach ($session['files'] as $k => $v) {
  535. $temp_path = 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/'.$v;
  536. if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $temp_path) > 0){
  537. $temp_path = iconv('utf-8','gbk', $temp_path);
  538. }
  539. if(!file_exists($temp_path)) {
  540. return error("", "文件缺失!");
  541. }
  542. }
  543. dir_mkdir('upload/backup/release');
  544. //文件备份
  545. $this->backOriginalFile('upload/upgrade/'.$session['sys_version'].'/'.$session['sys_release'].'/release', 'upload/upgrade/'.$session['sys_version'].'/'.$session['sys_release'].'/release/','upload/backup/release/');
  546. return json(['code' => 0]);
  547. }
  548. } catch (Exception $e){
  549. return json(['code' => -1, 'message' => $e->getMessage()]);
  550. }
  551. }
  552. /**
  553. * 备份文件
  554. * @param $from_path
  555. * @param $replace_path 将替换的
  556. * @param $to_path
  557. */
  558. public function backOriginalFile($from_path, $replace_path, $to_path){
  559. try{
  560. //得到原文件的文件结构
  561. //1、首先先读取文件夹
  562. $temp = scandir($from_path);
  563. //遍历文件夹
  564. foreach($temp as $v){
  565. $temp = $from_path . '/' . $v;
  566. $temp_path = substr_replace($temp,"", strpos($temp,$replace_path), strlen($replace_path));
  567. if(is_dir($temp)) {//如果是文件夹则执行
  568. if($v=='.' || $v=='..'){//判断是否为系统隐藏的文件.和.. 如果是则跳过否则就继续往下走,防止无限循环再这里。
  569. continue;
  570. }
  571. if(is_dir($temp_path)) {
  572. dir_mkdir($to_path.$temp_path);
  573. }
  574. $this->backOriginalFile($temp, $replace_path, $to_path);//因为是文件夹所以再次调用自己这个函数,把这个文件夹下的文件遍历出来
  575. }else{
  576. if(file_exists($temp_path)){
  577. copy($temp_path,$to_path . $temp_path);
  578. }
  579. }
  580. }
  581. } catch (Exception $e){
  582. return json(['code' => -1, 'message' => $e->getMessage()]);
  583. }
  584. }
  585. /**
  586. * 备份数据库
  587. * @return mixed[]|string[]
  588. */
  589. public function backupSql(){
  590. try{
  591. $database = new Database();
  592. ini_set('memory_limit','500M');
  593. $size = 300;
  594. $volumn = 1024 * 1024 * 2;
  595. $dump = '';
  596. $last_table = input('last_table', '');
  597. $series = max(1, input('series', 1));
  598. if (empty($last_table)) {
  599. $catch = true;
  600. } else {
  601. $catch = false;
  602. }
  603. $bakdir = 'upload/backup/sql';
  604. if (!is_dir($bakdir)) {
  605. dir_mkdir($bakdir);
  606. }
  607. $tables = $database->getDatabaseList();
  608. if (empty($tables)) {
  609. return json(["code" => 0]);
  610. }
  611. foreach ($tables as $table) {
  612. $table = array_shift( $table);
  613. if (!empty($last_table) && $table == $last_table) {
  614. $catch = true;
  615. }
  616. if (!$catch) {
  617. continue;
  618. }
  619. if (!empty($dump)) {
  620. $dump .= "\n\n";
  621. }
  622. if ($table != $last_table) {
  623. $row = $database->getTableSchemas($table);
  624. $dump .= $row;
  625. }
  626. $index = 0;
  627. if (!empty(input('index'))) {
  628. $index = input('index');
  629. }
  630. //枚举所有表的INSERT语句
  631. while (true) {
  632. $start = $index * $size;
  633. $result = $database->getTableInsertSql($table, $start, $size);
  634. if (!empty($result)) {
  635. $dump .= $result['data'];
  636. if (strlen($dump) > $volumn) {
  637. $bakfile = "upload/backup/sql/backup-{$series}.sql";
  638. $dump .= "\n\n";
  639. file_put_contents($bakfile, $dump);
  640. ++$series;
  641. ++$index;
  642. $current = array(
  643. 'last_table' => $table,
  644. 'index' => $index,
  645. 'series' => $series,
  646. );
  647. $current_series = $series - 1;
  648. return json(['data' => $current, 'code' => 0, 'message' => '正在导出数据, 请不要关闭浏览器, 当前第 ' . $current_series . ' 卷.']);
  649. }
  650. }
  651. if (empty($result) || count($result['result']) < $size) {
  652. break;
  653. }
  654. ++$index;
  655. }
  656. }
  657. $bakfile = "upload/backup/sql/backup-{$series}.sql";
  658. $dump .= "\n\n----MySQL Dump End";
  659. file_put_contents($bakfile, $dump);
  660. return json(['code' => 10, 'message' => '数据库备份完成']);
  661. } catch (Exception $e){
  662. return json(['code' => -1, 'message' => $e->getMessage()]);
  663. }
  664. }
  665. /**
  666. * 下载文件
  667. * @return array|bool|string
  668. */
  669. public function download() {
  670. if (request()->isAjax()) {
  671. try{
  672. $index = input("index", 0);
  673. $session = session("version_update");
  674. if(!empty($session)) {
  675. $up_model = new UpgradeModel();
  676. $file = isset($session['files'][$index]) ? $session['files'][$index] : '';
  677. if(empty($file)) {
  678. return json(['code' => 10, 'message' => 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/']);
  679. }
  680. $data = array(
  681. 'file' => $file,
  682. "version_release" => $session["sys_release"],
  683. "module_mark" => $session["sys_version"],
  684. "token" => $session["token"]
  685. );
  686. $info = $up_model->download($data);//异步下载更新文件
  687. //下载文件失败
  688. if(empty($info["data"]))
  689. return json($info);
  690. $file_path = dirname($file);
  691. $info = base64_decode($info['data']);
  692. $dir_make = dir_mkdir('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/' . $file_path);
  693. if($dir_make) {
  694. if(!empty($info)) {
  695. $temp_path = 'upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release/' . $file;
  696. if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $temp_path) > 0) {
  697. $temp_path = iconv('utf-8','gbk',$temp_path);
  698. }
  699. file_put_contents($temp_path, $info);
  700. return json(['code' => 0, 'message' => $file]);
  701. } else {
  702. return json(['code' => -1, 'message' => '升级文件不存在']);
  703. }
  704. } else {
  705. return json(['code' => -1, 'message' => '文件读写权限不足']);
  706. }
  707. } else {
  708. return json(['code' => -1, 'message' => '当前没有可升级的文件']);
  709. }
  710. } catch (Exception $e) {
  711. return json(['code' => -1, 'message' => $e->getMessage()]);
  712. }
  713. }
  714. }
  715. /**
  716. * 更新文件覆盖
  717. * @return mixed[]|string[]
  718. */
  719. public function executeFile(){
  720. try{
  721. $session = session("version_update");
  722. if(!empty($session)) {
  723. //文件替换
  724. dir_copy('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/release', './');
  725. return json(['code' => 0]);
  726. }
  727. } catch (Exception $e){
  728. return json(['code' => -1, 'message' => $e->getMessage()]);
  729. }
  730. }
  731. /**
  732. * 更新sql 执行
  733. * @return mixed[]|string[]
  734. */
  735. public function executeSql(){
  736. try{
  737. $session = session("version_update");
  738. if(!empty($session)) {
  739. //执行数据库
  740. $sql = check_bom('upload/upgrade/' . $session['sys_version'] . '/' . $session['sys_release'] . '/db_upgrade.sql');
  741. $sql_arr = parse_sql($sql);
  742. // 数据库表前缀
  743. $prefix = config("database")["connections"]["mysql"]["prefix"];
  744. foreach($sql_arr as $k => $v){
  745. $v = trim($v);
  746. if(!empty($v) && $v != ""){
  747. $v = str_replace('{{prefix}}', $prefix, $v);
  748. Db::execute($v);
  749. }
  750. }
  751. //更新菜单
  752. $menu = new Menu();
  753. $menu->refreshMenu('shop', '');
  754. $menu->refreshMenu('admin', '');
  755. //刷新店铺端权限组
  756. $shop_group_model = new ShopGroupModel();
  757. $shop_group_model->refreshGroup();
  758. return json(['code' => 0]);
  759. }
  760. } catch (Exception $e){
  761. return json(['code' => -1, 'message' => $e->getMessage()]);
  762. }
  763. }
  764. /**
  765. * 更新结束
  766. */
  767. public function upgradeEnd(){
  768. session("version_update", null);
  769. //清除缓存
  770. Cache::clear();
  771. return json(['code' => 0]);
  772. }
  773. /**
  774. * 版本恢复
  775. */
  776. public function versionRecovery(){
  777. try{
  778. //回滚备份的文件
  779. if(dir_is_empty('upload/backup/')){
  780. return json(['code' => -1, '没有可会滚得备份!']);
  781. }
  782. dir_copy('upload/backup/release', './');
  783. //回滚执行的sql语句
  784. $path = "upload/backup/sql";
  785. $flag = \FilesystemIterator::KEY_AS_FILENAME;
  786. $glob = new \FilesystemIterator($path, $flag);
  787. foreach ($glob as $name => $sql) {
  788. $sql_path = $path . '/' . $name;
  789. $sql = file_get_contents($sql_path);
  790. Db::execute($sql);
  791. }
  792. return json(['code' => 0, 'message' => '备份回滚成功!']);
  793. } catch (Exception $e){
  794. return json(['code' => -1, 'message' => $e->getMessage()]);
  795. }
  796. }
  797. /**
  798. * 刷新菜单 测试
  799. */
  800. public function refresh()
  801. {
  802. $menu = new Menu();
  803. $res = $menu->refreshMenu('admin', '');
  804. var_dump($res);
  805. }
  806. /**
  807. * 刷新自定义模板 测试
  808. */
  809. public function refreshDiy()
  810. {
  811. $addon = new Addon();
  812. $res = $addon->refreshDiyView('');
  813. var_dump($res);
  814. }
  815. }