VersionUpdate.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\command;
  12. use think\console\Command;
  13. use think\console\Input;
  14. use think\console\input\Option;
  15. use think\console\Output;
  16. use think\Exception;
  17. use think\facade\Db;
  18. class VersionUpdate extends Command
  19. {
  20. protected function configure()
  21. {
  22. $this->setName('version:update')
  23. ->setDescription('crmeb_merchant 版本更新命令')
  24. ->addOption('package', 'p', Option::VALUE_REQUIRED, '指定更新包的路径');
  25. }
  26. /**
  27. * 版本升级
  28. * @param Input $input
  29. * @param Output $output
  30. * @return int|void|null
  31. * @author wuhaotian
  32. * @email 442384644@qq.com
  33. * @date 2024/7/12
  34. */
  35. protected function execute(Input $input, Output $output)
  36. {
  37. $flag = $output->confirm($input, '更新之前请务必做好数据库和代码的备份,防止数据或代码在更新中被覆盖 !!!', false);
  38. if (!$flag) return;
  39. $flag = $output->confirm($input, '请确保swoole服务和队列服务已关闭,防止意外报错', false);
  40. if (!$flag) return;
  41. $version = get_crmeb_version_code();
  42. ini_set('memory_limit', '-1');
  43. set_time_limit(0);
  44. $packagePath = $input->getOption('package') ?: 'auto_update.zip';
  45. $updateFilePath = app()->getRootPath() . ltrim($packagePath, '/= ');
  46. $updatePath = dirname($updateFilePath);
  47. $unzipPath = $updatePath . '/_update_runtime_' . str_replace('.', '_', $version);
  48. if (!is_file($updateFilePath)) {
  49. $output->warning($updateFilePath . ' 更新包不存在');
  50. return;
  51. }
  52. $zip = new \ZipArchive();
  53. if ($zip->open($updateFilePath) === true) {
  54. $zip->extractTo($unzipPath);
  55. $zip->close();
  56. } else {
  57. $output->warning($updateFilePath . ' 更新包打开失败');
  58. return;
  59. }
  60. $unlink = function () use ($unzipPath) {
  61. @unlink($unzipPath . '/update.sql');
  62. @unlink($unzipPath . '/update.zip');
  63. @unlink($unzipPath . '/AutoUpdate.php');
  64. @unlink($unzipPath . '/.env');
  65. @unlink($unzipPath . '/.config');
  66. @rmdir($unzipPath);
  67. };
  68. if (!is_file($unzipPath . '/.env') && !is_file($unzipPath . '/.config')) {
  69. $output->warning('文件不完整');
  70. $unlink();
  71. return;
  72. }
  73. if (is_file($unzipPath . '/.env')) {
  74. $env = parse_ini_file($unzipPath . '/.env', true) ?: [];
  75. }
  76. if (is_file($unzipPath . '/.config')) {
  77. $env = parse_ini_file($unzipPath . '/.config', true) ?: [];
  78. }
  79. if (($env['NAME'] ?? '') !== 'CRMEB-MERCHANT') {
  80. $output->warning('(1)版本号对比失败,请检查当前版本号(.version/更新包)是否被修改');
  81. $unlink();
  82. }
  83. if (($env['TYPE'] ?? '') !== 'MODEL') {
  84. if (!($env['OLD_VERSION'] ?? '')) {
  85. $output->warning('(2)版本号对比失败,请检查当前版本号(.version/更新包)是否被修改');
  86. $unlink();
  87. }
  88. if ($env['OLD_VERSION'] !== $version) {
  89. if (($env['UPDATE_VERSION']?? '') == $version) {
  90. $r = $output->confirm($input, '当前版本号和升级包版本号一致,是否重新覆盖操作???', false);
  91. if (!$r) return;
  92. } else {
  93. $output->warning('(2)版本号对比失败,请检查当前版本号(.version/更新包)是否被修改');
  94. $unlink();
  95. }
  96. }
  97. }
  98. $r = true;
  99. $confirm = [];
  100. if (isset($env['confirm'])) {
  101. $confirm = is_array($env['confirm']) ? $env['confirm'] : [$env['confirm']];
  102. }
  103. foreach ($confirm as $item) {
  104. if (!$output->confirm($input, $item, false)) {
  105. $unlink();
  106. return;
  107. }
  108. }
  109. $installHost = systemConfig('site_url');
  110. if (substr($installHost, 0, 5) == 'https'){
  111. $_url = str_replace('//' ,'\\\/\\\/', $installHost);
  112. } else {
  113. $_url = str_replace('http://' ,'http:\\\/\\\/', $installHost);
  114. }
  115. if (is_file($unzipPath . '/update.sql')) {
  116. $str = preg_replace('/--.*/i', '', file_get_contents($unzipPath . '/update.sql'));
  117. $str = preg_replace('/\/\*.*\*\/(\;)?/i', '', $str);
  118. $sqlList = explode(";\n", $str);
  119. } else {
  120. $sqlList = [];
  121. }
  122. $autoUpdateData = null;
  123. if (is_file($unzipPath . '/AutoUpdate.php')) {
  124. try {
  125. require_once $unzipPath . '/AutoUpdate.php';
  126. $autoUpdateData = new \crmeb\update\AutoUpdate($input, $output);
  127. } catch (\Throwable $e) {}
  128. }
  129. if ($autoUpdateData) $autoUpdateData->autoUpdateStart();
  130. $output->info('开始更新');
  131. $pre = env('database.prefix');
  132. try {
  133. Db::transaction(function () use ($pre, $output, $unzipPath, $sqlList, $autoUpdateData, $installHost, $_url, $r) {
  134. if ($autoUpdateData) $autoUpdateData->autoUpdateBefore();
  135. $count = count($sqlList);
  136. if ($count && $autoUpdateData) {
  137. $autoUpdateData->autoSqlBefore();
  138. }
  139. foreach ($sqlList as $idx => $sql) {
  140. $sql = trim($sql, " \xEF\xBB\xBF\r\n");
  141. if (!$sql) continue;
  142. if ($pre && $pre !== 'eb_') {
  143. $sql = str_replace('eb_', $pre, $sql);
  144. }
  145. $sql = str_replace('https://mer1.crmeb.net', $installHost , $sql);
  146. $sql = str_replace('https:\\\/\\\/mer1.crmeb.net', $_url , $sql);
  147. try{
  148. Db::query($sql . ';');
  149. }catch (\Exception $e) {
  150. if (!$r) throw new Exception($e->getMessage());
  151. }
  152. if (!($idx % 50)) {
  153. $output->info("导入中($idx/$count)");
  154. }
  155. }
  156. if ($count) {
  157. if ($autoUpdateData) $autoUpdateData->autoSqlAfter();
  158. $output->info('数据库更新成功');
  159. }
  160. $zip = new \ZipArchive();
  161. if ($zip->open($unzipPath . '/update.zip') === true) {
  162. if ($autoUpdateData) $autoUpdateData->autoCopyBefore();
  163. $zip->extractTo(app()->getRootPath());
  164. $zip->close();
  165. if ($autoUpdateData) $autoUpdateData->autoCopyAfter();
  166. } else {
  167. throw new Exception('更新文件覆盖失败');
  168. }
  169. });
  170. if ($autoUpdateData) $autoUpdateData->autoUpdateAfter();
  171. } catch (\Throwable $e) {
  172. $output->warning('更新失败:' . $e->getMessage());
  173. $unlink();
  174. if ($autoUpdateData) $autoUpdateData->autoUpdateFail($e);
  175. return;
  176. }
  177. $unlink();
  178. if ($autoUpdateData) $autoUpdateData->autoUpdateEnd();
  179. $output->info('版本更新成功, 请重启swoole服务和队列服务');
  180. update_crmeb_compiled();
  181. }
  182. }