Config.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. namespace app\admin\controller\routine;
  3. use Throwable;
  4. use ba\Filesystem;
  5. use app\common\library\Email;
  6. use PHPMailer\PHPMailer\PHPMailer;
  7. use app\common\controller\Backend;
  8. use app\admin\model\Config as ConfigModel;
  9. use PHPMailer\PHPMailer\Exception as PHPMailerException;
  10. class Config extends Backend
  11. {
  12. /**
  13. * @var object
  14. * @phpstan-var ConfigModel
  15. */
  16. protected object $model;
  17. protected array $noNeedLogin = ['index'];
  18. protected array $filePath = [
  19. 'appConfig' => 'config/app.php',
  20. 'webAdminBase' => 'web/src/router/static/adminBase.ts',
  21. 'backendEntranceStub' => 'app/admin/library/stubs/backendEntrance.stub',
  22. ];
  23. public function initialize(): void
  24. {
  25. parent::initialize();
  26. $this->model = new ConfigModel();
  27. }
  28. public function index(): void
  29. {
  30. $configGroup = get_sys_config('config_group');
  31. $config = $this->model->order('weigh desc')->select()->toArray();
  32. $list = [];
  33. $newConfigGroup = [];
  34. foreach ($configGroup as $item) {
  35. $list[$item['key']]['name'] = $item['key'];
  36. $list[$item['key']]['title'] = __($item['value']);
  37. $newConfigGroup[$item['key']] = $list[$item['key']]['title'];
  38. }
  39. foreach ($config as $item) {
  40. if (array_key_exists($item['group'], $newConfigGroup)) {
  41. $item['title'] = __($item['title']);
  42. $list[$item['group']]['list'][] = $item;
  43. }
  44. }
  45. $this->success('', [
  46. 'list' => $list,
  47. 'remark' => get_route_remark(),
  48. 'configGroup' => $newConfigGroup ?? [],
  49. 'quickEntrance' => get_sys_config('config_quick_entrance'),
  50. ]);
  51. }
  52. /**
  53. * 编辑
  54. * @throws Throwable
  55. */
  56. public function edit(): void
  57. {
  58. $all = $this->model->select();
  59. foreach ($all as $item) {
  60. if ($item['type'] == 'editor') {
  61. $this->request->filter('clean_xss');
  62. break;
  63. }
  64. }
  65. if ($this->request->isPost()) {
  66. $this->modelValidate = false;
  67. $data = $this->request->post();
  68. if (!$data) {
  69. $this->error(__('Parameter %s can not be empty', ['']));
  70. }
  71. $data = $this->excludeFields($data);
  72. $configValue = [];
  73. foreach ($all as $item) {
  74. if (array_key_exists($item->name, $data)) {
  75. $configValue[] = [
  76. 'id' => $item->id,
  77. 'type' => $item->getData('type'),
  78. 'value' => $data[$item->name]
  79. ];
  80. // 自定义后台入口
  81. if ($item->name == 'backend_entrance') {
  82. $backendEntrance = get_sys_config('backend_entrance');
  83. if ($backendEntrance == $data[$item->name]) continue;
  84. if (!preg_match("/^\/[a-zA-Z0-9]+$/", $data[$item->name])) {
  85. $this->error(__('Backend entrance rule'));
  86. }
  87. // 修改 adminBaseRoutePath
  88. $adminBaseFilePath = Filesystem::fsFit(root_path() . $this->filePath['webAdminBase']);
  89. $adminBaseContent = @file_get_contents($adminBaseFilePath);
  90. if (!$adminBaseContent) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']]));
  91. $adminBaseContent = str_replace("export const adminBaseRoutePath = '$backendEntrance'", "export const adminBaseRoutePath = '{$data[$item->name]}'", $adminBaseContent);
  92. $result = @file_put_contents($adminBaseFilePath, $adminBaseContent);
  93. if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']]));
  94. // 去除后台入口开头的斜杠
  95. $oldBackendEntrance = ltrim($backendEntrance, '/');
  96. $newBackendEntrance = ltrim($data[$item->name], '/');
  97. // 禁止 admin 应用访问
  98. $denyAppList = config('app.deny_app_list');
  99. if (($newBackendEntrance == 'admin' && in_array('admin', $denyAppList)) || !in_array('admin', $denyAppList)) {
  100. $appConfigFilePath = Filesystem::fsFit(root_path() . $this->filePath['appConfig']);
  101. $appConfigContent = @file_get_contents($appConfigFilePath);
  102. if (!$appConfigContent) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']]));
  103. $denyAppListStr = '';
  104. foreach ($denyAppList as $appName) {
  105. if ($newBackendEntrance == 'admin' && $appName == 'admin') continue;
  106. $denyAppListStr .= "'$appName', ";
  107. }
  108. if ($newBackendEntrance != 'admin') $denyAppListStr .= "'admin', ";
  109. $denyAppListStr = rtrim($denyAppListStr, ', ');
  110. $denyAppListStr = "[$denyAppListStr]";
  111. $appConfigContent = preg_replace("/'deny_app_list'(\s+)=>(\s+)(.*)/", "'deny_app_list'\$1=>\$2$denyAppListStr,", $appConfigContent);
  112. $result = @file_put_contents($appConfigFilePath, $appConfigContent);
  113. if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']]));
  114. }
  115. // 建立API入口文件
  116. $oldBackendEntranceFile = Filesystem::fsFit(public_path() . $oldBackendEntrance . '.php');
  117. $newBackendEntranceFile = Filesystem::fsFit(public_path() . $newBackendEntrance . '.php');
  118. if (file_exists($oldBackendEntranceFile)) @unlink($oldBackendEntranceFile);
  119. if ($newBackendEntrance != 'admin') {
  120. $backendEntranceStub = @file_get_contents(Filesystem::fsFit(root_path() . $this->filePath['backendEntranceStub']));
  121. if (!$backendEntranceStub) $this->error(__('Configuration write failed: %s', [$this->filePath['backendEntranceStub']]));
  122. $result = @file_put_contents($newBackendEntranceFile, $backendEntranceStub);
  123. if (!$result) $this->error(__('Configuration write failed: %s', [$newBackendEntranceFile]));
  124. }
  125. }
  126. }
  127. }
  128. $result = false;
  129. $this->model->startTrans();
  130. try {
  131. // 模型验证
  132. if ($this->modelValidate) {
  133. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  134. if (class_exists($validate)) {
  135. $validate = new $validate;
  136. if ($this->modelSceneValidate) $validate->scene('edit');
  137. $validate->check($data);
  138. }
  139. }
  140. $result = $this->model->saveAll($configValue);
  141. $this->model->commit();
  142. } catch (Throwable $e) {
  143. $this->model->rollback();
  144. $this->error($e->getMessage());
  145. }
  146. if ($result !== false) {
  147. $this->success(__('The current page configuration item was updated successfully'));
  148. } else {
  149. $this->error(__('No rows updated'));
  150. }
  151. }
  152. }
  153. public function add(): void
  154. {
  155. if ($this->request->isPost()) {
  156. $data = $this->request->post();
  157. if (!$data) {
  158. $this->error(__('Parameter %s can not be empty', ['']));
  159. }
  160. $data = $this->excludeFields($data);
  161. $result = false;
  162. $this->model->startTrans();
  163. try {
  164. // 模型验证
  165. if ($this->modelValidate) {
  166. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  167. if (class_exists($validate)) {
  168. $validate = new $validate;
  169. if ($this->modelSceneValidate) $validate->scene('add');
  170. $validate->check($data);
  171. }
  172. }
  173. $result = $this->model->save($data);
  174. $this->model->commit();
  175. } catch (Throwable $e) {
  176. $this->model->rollback();
  177. $this->error($e->getMessage());
  178. }
  179. if ($result !== false) {
  180. $this->success(__('Added successfully'));
  181. } else {
  182. $this->error(__('No rows were added'));
  183. }
  184. }
  185. $this->error(__('Parameter error'));
  186. }
  187. /**
  188. * 发送邮件测试
  189. * @throws Throwable
  190. */
  191. public function sendTestMail(): void
  192. {
  193. $data = $this->request->post();
  194. $mail = new Email();
  195. try {
  196. $mail->Host = $data['smtp_server'];
  197. $mail->SMTPAuth = true;
  198. $mail->Username = $data['smtp_user'];
  199. $mail->Password = $data['smtp_pass'];
  200. $mail->SMTPSecure = $data['smtp_verification'] == 'SSL' ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS;
  201. $mail->Port = $data['smtp_port'];
  202. $mail->setFrom($data['smtp_sender_mail'], $data['smtp_user']);
  203. $mail->isSMTP();
  204. $mail->addAddress($data['testMail']);
  205. $mail->isHTML();
  206. $mail->setSubject(__('This is a test email') . '-' . get_sys_config('site_name'));
  207. $mail->Body = __('Congratulations, receiving this email means that your email service has been configured correctly');
  208. $mail->send();
  209. } catch (PHPMailerException) {
  210. $this->error($mail->ErrorInfo);
  211. }
  212. $this->success(__('Test mail sent successfully~'));
  213. }
  214. }