better-staridc-MNBT
1<?php
2if($egn=='gglist') {
3 include("../cf_up.php");
4 $result = send_post($mn_conf['aet'].'://'.$mn_conf['url'].':'.$mn_conf['port'].'/'.$mn_conf['install_wj'].'/guanggao.php',[]);
5 if($result===false) $result='';
6 exit($result);
7}
8if($egn=='update') {
9 // 更新包体积大、解压慢,先放宽执行时间;用户中途关页面也要把流程走完
10 @set_time_limit(600);
11 @ignore_user_abort(true);
12 include("../MPHX/BL.php");
13 include_once("../MPHX/github_updater.php");
14 include_once("../MPHX/migrations.php");
15 include("../cf_up.php");
16
17 mnbt_updater_guard_start();
18 $up_cfg = mnbt_updater_config();
19 // 用真实路径做文件操作,ROOT 万一是软链或大小写不同也不会把文件写到别处
20 $root_real = str_replace('\\', '/', realpath(rtrim(mnbt_updater_root(),'/')) ?: rtrim(mnbt_updater_root(),'/'));
21 $root_sl = $root_real.'/'; // 站点根,带尾斜杠
22 $root = $root_real; // 站点根,不带尾斜杠
23 mnbt_updater_guard('root',$root_sl);
24
25 // 1. 检查最新版本(只走 GitHub Release,不再校验 authcode);执行更新前必须拿最新的下载地址
26 $chk = mnbt_updater_check(true);
27 if(!$chk['ok']) {
28 mnbt_updater_guard_done();
29 json_exit_error('检查更新失败:'.$chk['error']);
30 }
31 if(!$chk['can_update']) {
32 mnbt_updater_guard_done();
33 json_exit_error('当前已是最新版本('.$chk['current'].'),无需更新');
34 }
35
36 // 2. 临时目录放站点根的 runtime/temp 下(已在 .gitignore 内,且后台目录改名后依然可访问)
37 $tmp_dir = $root.'/runtime/temp/update_tmp';
38 if(!is_dir($tmp_dir) && !mnbt_updater_mkdir($tmp_dir)) {
39 mnbt_updater_guard_done();
40 json_exit_error('临时目录创建失败,请检查 runtime 目录权限');
41 }
42 $zip_file = $tmp_dir.'/gxwj-'.mt_rand(100000,999999).'.zip';
43 mnbt_updater_guard('zip',$zip_file);
44
45 // 3. 下载:Release 附件优先,回落自动源码包;每个来源按 github 直连、配置镜像顺序依次尝试
46 $used = null;
47 $tried = [];
48 foreach($chk['candidates'] as $c) {
49 $e = '';
50 if(mnbt_updater_download($c['url'],$zip_file,$up_cfg,$e)) {
51 $used = $c;
52 break;
53 }
54 $tried[] = ($c['via']==='mirror' ? $c['mirror'] : 'github 直连').':'.$e;
55 }
56 if($used === null) {
57 mnbt_updater_guard_rollback();
58 mnbt_updater_guard_done();
59 json_exit_error('更新包下载失败(已尝试 '.count($tried).' 个来源):'.implode(' / ',$tried));
60 }
61
62 // 4. 解压前校验:拒绝危险路径,识别并准备剥掉顶层目录
63 $za = mnbt_updater_zip_analyze($zip_file,$zerr);
64 if(!$za) {
65 mnbt_updater_guard_rollback();
66 mnbt_updater_guard_done();
67 json_exit_error('更新包校验失败:'.$zerr);
68 }
69
70 // 5. 备份本地文件:config.php、cf_up.php、MPHX/SQ.php、install/install.lock、api/cookie/
71 $bak_dir = $tmp_dir.'/bak_'.mt_rand(100000,999999);
72 $backup = mnbt_updater_backup_local($root_sl,$bak_dir,$bk_err);
73 mnbt_updater_guard('bak',$bak_dir);
74 mnbt_updater_guard('backup',$backup);
75 if($bk_err!=='') {
76 mnbt_updater_guard_rollback();
77 mnbt_updater_guard_done();
78 json_exit_error('本地配置备份失败:'.$bk_err);
79 }
80
81 // 6. 当前后台目录改名成标准的 admin,新包里的 admin 才能落在正确位置
82 $admin_now = str_replace('\\','/',dirname(__DIR__));
83 $admin_std = $root.'/admin';
84 mnbt_updater_guard('admin_now',$admin_std);
85 mnbt_updater_guard('admin_orig',$admin_now);
86 if(basename($admin_now)!=='admin' || strcasecmp(dirname($admin_now),$root)!==0) {
87 if(is_dir($admin_std)) {
88 mnbt_updater_guard_rollback();
89 mnbt_updater_guard_done();
90 json_exit_error('站点根目录已存在一个 admin 目录,与当前后台目录名冲突,已中止更新');
91 }
92 if(!@rename($admin_now,$admin_std)) {
93 mnbt_updater_guard_rollback();
94 mnbt_updater_guard_done();
95 json_exit_error('后台目录改名失败,已中止更新');
96 }
97 mnbt_updater_guard('moved',1);
98 }
99
100 // 7. 解压覆盖到站点根(附件包 zip 根即站点根;源码包剥掉顶层目录后同样如此)
101 if(!mnbt_updater_extract($zip_file,$root_sl,$za['strip'],$ex_err)) {
102 mnbt_updater_guard_rollback();
103 mnbt_updater_guard_done();
104 json_exit_error('解压覆盖失败:'.$ex_err);
105 }
106
107 // 8. 升级 SQL:把包里 update/ 的版本化迁移文件按游标顺序跑一遍(支持跨版本一步跳)
108 $sql_msg = '';
109 $upd_dir = $root.'/update/';
110 $applied_files = array();
111 if(is_dir($upd_dir)) {
112 $applied_files = mnbt_migrations_run($dbconfig,$upd_dir,(int)$chk['version'],$mig_err);
113 if($mig_err!=='') $sql_msg = $mig_err;
114 // 遗留单文件 update.sql(旧式发布)继续兼容:链成功后一次性执行并删除
115 if($sql_msg==='' && is_file($upd_dir.'update.sql')) {
116 $sql_msg = mnbt_updater_run_sql($upd_dir.'update.sql',$dbconfig);
117 if($sql_msg==='') {
118 @unlink($upd_dir.'update.sql');
119 @rmdir($upd_dir);
120 }
121 } elseif($sql_msg==='') {
122 // 版本链全部成功:删掉已应用的迁移文件,保持 update/ 目录整洁(游标表已记账,重跑无副作用)
123 foreach($applied_files as $fn) @unlink($upd_dir.$fn);
124 @rmdir($upd_dir);
125 }
126 // 失败:保留 update/ 目录所有文件,游标停在最后成功版本,修复后可再次点击继续
127 }
128
129 // 9. 还原本地配置与安装锁、把后台目录改回原名、清临时文件
130 mnbt_updater_guard_rollback();
131 mnbt_updater_guard_done();
132
133 $via_label = $used['via']==='mirror' ? $used['mirror'] : 'github 直连';
134 if(function_exists('logjl')) {
135 logjl($user ?? '', '系统更新', '更新到 '.$chk['latest'].'('.$used['label'].',来源 '.$via_label.')', $sql_msg===''?'更新成功':'更新成功但升级SQL有误', $DB);
136 }
137 if($sql_msg!=='') {
138 json_exit_error('文件已更新,但升级 SQL 执行失败:'.$sql_msg.'(update/ 迁移文件已保留,游标停在最后成功的版本,可修复后重跑或手工执行)', [
139 'ver' => $chk['latest'], 'tag' => $chk['tag'],
140 'source' => $used['label'], 'via' => $via_label, 'strip' => $za['strip'], 'files' => $za['files'],
141 ]);
142 }
143 json_exit('更新成功~请手动刷新页面', [
144 'qk' => 1, 'ver' => $chk['latest'], 'tag' => $chk['tag'],
145 'source' => $used['label'], 'via' => $via_label, 'strip' => $za['strip'], 'files' => $za['files'],
146 ]);
147 return;
148}
149return;