Переглянути джерело

chore: code clean up(thanks JB!)

M1Screw 2 роки тому
батько
коміт
3bb9b95d04
100 змінених файлів з 836 додано та 3042 видалено
  1. 1 1
      app/envload.php
  2. 2 2
      app/predefine.php
  3. 6 2
      composer.json
  4. 5 1
      console
  5. 2 2
      docker-compose.yml
  6. 1 0
      phpinsights.php
  7. 1 1
      public/assets/js/fuck.js
  8. 0 5
      public/theme/tabler/assets/js/_.js
  9. 0 5
      public/theme/tabler/assets/js/bootstrap.js
  10. 0 49
      public/theme/tabler/assets/js/form-floating-label.js
  11. 0 13
      public/theme/tabler/assets/js/form-textarea.js
  12. 0 12
      public/theme/tabler/assets/js/header.js
  13. 0 200
      public/theme/tabler/assets/js/menu.js
  14. 0 12
      public/theme/tabler/assets/js/modal.js
  15. 0 4
      public/theme/tabler/assets/js/picker.js
  16. 0 116
      public/theme/tabler/assets/js/snackbar.js
  17. 0 51
      public/theme/tabler/assets/js/tab.js
  18. 0 181
      public/theme/tabler/assets/js/tile.js
  19. 0 5
      public/theme/tabler/assets/js/wave.js
  20. BIN
      public/theme/tabler/css/images/bg/geometry.jpg
  21. BIN
      public/theme/tabler/css/images/bg/streak.jpg
  22. 0 1
      public/theme/tabler/css/user.css
  23. 0 0
      public/theme/tabler/css/user.min.css
  24. BIN
      public/theme/tabler/images/users/trafficbar.png
  25. 0 0
      public/theme/tabler/js/base.js
  26. 0 0
      public/theme/tabler/js/base.min.js
  27. 0 1
      public/theme/tabler/js/jquery.qrcode.min.js
  28. 1 1
      resources/views/tabler/admin/announcement/index.tpl
  29. 3 3
      resources/views/tabler/admin/coupon.tpl
  30. 1 1
      resources/views/tabler/admin/detect.tpl
  31. 0 17
      resources/views/tabler/admin/footer.tpl
  32. 2 2
      resources/views/tabler/admin/giftcard.tpl
  33. 0 0
      resources/views/tabler/admin/log/detect.tpl
  34. 0 114
      resources/views/tabler/admin/main.tpl
  35. 2 2
      resources/views/tabler/admin/node/index.tpl
  36. 2 2
      resources/views/tabler/admin/order/index.tpl
  37. 2 2
      resources/views/tabler/admin/product/index.tpl
  38. 0 90
      resources/views/tabler/admin/shop/bought.tpl
  39. 0 238
      resources/views/tabler/admin/shop/create.tpl
  40. 0 251
      resources/views/tabler/admin/shop/edit.tpl
  41. 0 98
      resources/views/tabler/admin/shop/index.tpl
  42. 2 2
      resources/views/tabler/admin/ticket/index.tpl
  43. 1 1
      resources/views/tabler/admin/user/index.tpl
  44. 1 1
      resources/views/tabler/live_chat.tpl
  45. 0 216
      resources/views/tabler/telegram_error.tpl
  46. 0 216
      resources/views/tabler/telegram_success.tpl
  47. 23 25
      src/Command/ClientDownload.php
  48. 22 15
      src/Command/Cron.php
  49. 15 5
      src/Command/DetectBan.php
  50. 18 6
      src/Command/DetectGFW.php
  51. 1 1
      src/Command/FinanceMail.php
  52. 36 25
      src/Command/Job.php
  53. 3 5
      src/Command/Migration.php
  54. 45 21
      src/Command/Tool.php
  55. 1 1
      src/Command/Update.php
  56. 16 18
      src/Controllers/Admin/AnnController.php
  57. 0 9
      src/Controllers/Admin/ApiController.php
  58. 27 12
      src/Controllers/Admin/DetectController.php
  59. 10 14
      src/Controllers/Admin/InviteController.php
  60. 13 14
      src/Controllers/Admin/IpController.php
  61. 11 18
      src/Controllers/Admin/NodeController.php
  62. 16 10
      src/Controllers/Admin/Setting/BillingController.php
  63. 9 4
      src/Controllers/Admin/Setting/CaptchaController.php
  64. 12 8
      src/Controllers/Admin/Setting/EmailController.php
  65. 9 4
      src/Controllers/Admin/Setting/FeatureController.php
  66. 9 4
      src/Controllers/Admin/Setting/ImController.php
  67. 9 4
      src/Controllers/Admin/Setting/RefController.php
  68. 9 4
      src/Controllers/Admin/Setting/RegController.php
  69. 9 4
      src/Controllers/Admin/Setting/SupportController.php
  70. 0 370
      src/Controllers/Admin/ShopController.php
  71. 3 4
      src/Controllers/Admin/SubscribeLogController.php
  72. 17 19
      src/Controllers/Admin/TicketController.php
  73. 3 4
      src/Controllers/Admin/TrafficLogController.php
  74. 22 33
      src/Controllers/Admin/UserController.php
  75. 3 2
      src/Controllers/AdminController.php
  76. 43 38
      src/Controllers/AuthController.php
  77. 2 2
      src/Controllers/BaseController.php
  78. 12 8
      src/Controllers/HomeController.php
  79. 60 67
      src/Controllers/LinkController.php
  80. 11 14
      src/Controllers/PasswordController.php
  81. 31 15
      src/Controllers/SubController.php
  82. 7 7
      src/Controllers/User/CouponController.php
  83. 4 2
      src/Controllers/User/DetectController.php
  84. 17 7
      src/Controllers/User/InvoiceController.php
  85. 6 4
      src/Controllers/User/LogController.php
  86. 24 13
      src/Controllers/User/MFAController.php
  87. 31 17
      src/Controllers/User/OrderController.php
  88. 8 2
      src/Controllers/User/ProductController.php
  89. 2 1
      src/Controllers/User/ServerController.php
  90. 13 18
      src/Controllers/User/ShopController.php
  91. 15 15
      src/Controllers/User/TicketController.php
  92. 69 124
      src/Controllers/UserController.php
  93. 8 25
      src/Controllers/WebAPI/FuncController.php
  94. 20 36
      src/Controllers/WebAPI/NodeController.php
  95. 14 10
      src/Controllers/WebAPI/UserController.php
  96. 8 2
      src/Middleware/ErrorHandler.php
  97. 1 1
      src/Middleware/NodeToken.php
  98. 10 8
      src/Models/Bought.php
  99. 10 16
      src/Models/Code.php
  100. 4 6
      src/Models/Coupon.php

+ 1 - 1
app/envload.php

@@ -7,7 +7,7 @@ if (getenv('UIM_ENV_REPLACE_ENABLE')) {
         global $_ENV;
         $envUpKey = strtoupper($envKey);
         // Key starts with UIM_
-        if (strpos($envUpKey, 'UIM_') === 0) {
+        if (str_starts_with($envUpKey, 'UIM_')) {
             // Valid env key, set to _ENV
             $configKey = substr($envUpKey, 4);
             $realKey = App\Utils\Tools::searchEnvName($configKey);

+ 2 - 2
app/predefine.php

@@ -6,5 +6,5 @@ declare(strict_types=1);
  * To define global variable
  */
 
-define('BASE_PATH', __DIR__ . '/..');
-define('VERSION', '2022.12.1');
+const BASE_PATH = __DIR__ . '/..';
+const VERSION = '2022.12.1';

+ 6 - 2
composer.json

@@ -5,6 +5,10 @@
         "ext-json": "*",
         "ext-mysqli": "*",
         "ext-xml": "*",
+        "ext-zip": "*",
+        "ext-openssl": "*",
+        "ext-bcmath": "*",
+        "ext-pdo": "*",
         "anankke/omnipay-alipay": "^3.1.3",
         "aws/aws-sdk-php": "^3",
         "cloudflare/sdk": "^1",
@@ -19,6 +23,7 @@
         "league/omnipay": "^3.2.1",
         "mailgun/mailgun-php": "^3",
         "phpmailer/phpmailer": "^6",
+        "postal/postal": "^1.0",
         "ramsey/uuid": "^4",
         "sendgrid/sendgrid": "^8",
         "sentry/sentry": "^3",
@@ -29,8 +34,7 @@
         "symfony/console": "*",
         "symfony/yaml": "^6",
         "vectorface/googleauthenticator": "^3.0",
-        "voku/anti-xss": "^4",
-        "postal/postal": "^1.0"
+        "voku/anti-xss": "^4"
     },
     "autoload": {
         "psr-4": {

+ 5 - 1
console

@@ -19,4 +19,8 @@ $application = new Application();
 
 // ... register commands
 
-$application->run();
+try {
+    $application->run();
+} catch (Exception $e) {
+    echo $e->getMessage();
+}

+ 2 - 2
docker-compose.yml

@@ -6,7 +6,7 @@ services:
         container_name: sspanel
         restart: always
         ports:
-            - 80:80
+            - "80:80"
         volumes:
             - ./config/.config.php:/var/www/config/.config.php
     mariadb:
@@ -21,6 +21,6 @@ services:
         container_name: phpmyadmin
         restart: always
         ports:
-          - 8080:80
+          - "8080:80"
         environment:
           - PMA_ARBITRARY=1

+ 1 - 0
phpinsights.php

@@ -15,6 +15,7 @@ return [
         PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\GlobalKeywordSniff::class,
         PhpCsFixer\Fixer\Import\OrderedImportsFixer::class,
         PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer::class,
+        SlevomatCodingStandard\Sniffs\Commenting\InlineDocCommentDeclarationSniff::class,
         SlevomatCodingStandard\Sniffs\ControlStructures\DisallowShortTernaryOperatorSniff::class,
         SlevomatCodingStandard\Sniffs\Classes\ForbiddenPublicPropertySniff::class,
         SlevomatCodingStandard\Sniffs\Classes\ModernClassNameReferenceSniff::class,

+ 1 - 1
public/assets/js/fuck.js

@@ -56,7 +56,7 @@
         hasMime('type', 'application/asx')
       ) {
         is360 = true;
-      };
+      }
     }
   }
 

Різницю між файлами не показано, бо вона завелика
+ 0 - 5
public/theme/tabler/assets/js/_.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 5
public/theme/tabler/assets/js/bootstrap.js


+ 0 - 49
public/theme/tabler/assets/js/form-floating-label.js

@@ -1,49 +0,0 @@
-// floating label
-	(function ($) {
-		'use strict';
-
-		$.fn.floatingLabel = function (option) {
-			var parent = this.closest('.form-group-label');
-
-			if (parent.length) {
-				switch (option) {
-					case 'focusin':
-						parent.addClass('control-focus');
-						break;
-					case 'focusout':
-						parent.removeClass('control-focus');
-						break;
-					default: 
-						if (this.val()) {
-							parent.addClass('control-highlight');
-						} else if (this.is('select') && $('option:first-child', this).html().replace(' ', '') !== '') {
-							parent.addClass('control-highlight');
-						} else {
-							parent.removeClass('control-highlight');
-						};
-				};
-			};
-
-			return this;
-		};
-	}(jQuery));
-
-	$(function () {
-		'use strict';
-
-		$('.form-group-label .form-control').each(function () {
-			$(this).floatingLabel('change');
-		});
-
-		$(document).on('change', '.form-group-label .form-control', function () {
-			$(this).floatingLabel('change');
-		});
-
-		$(document).on('focusin', '.form-group-label .form-control', function () {
-			$(this).floatingLabel('focusin');
-		});
-
-		$(document).on('focusout', '.form-group-label .form-control', function () {
-			$(this).floatingLabel('focusout');
-		});
-	});

+ 0 - 13
public/theme/tabler/assets/js/form-textarea.js

@@ -1,13 +0,0 @@
-/*!
- * textarea autosize v0.4.0
- * https://github.com/javierjulio/textarea-autosize
- */
-
-!function(t,e){function i(e){this.element=e,this.$element=t(e),this.init()}var n="textareaAutoSize",h="plugin_"+n,s=function(t){return t.replace(/\s/g,"").length>0};i.prototype={init:function(){var i=(this.$element.outerHeight(),parseInt(this.$element.css("paddingBottom"))+parseInt(this.$element.css("paddingTop")));s(this.element.value)&&this.$element.height(this.element.scrollHeight-i),this.$element.on("input keyup",function(){var n=t(e),h=n.scrollTop();t(this).height(0).height(this.scrollHeight-i),n.scrollTop(h)})}},t.fn[n]=function(e){return this.each(function(){t.data(this,h)||t.data(this,h,new i(this,e))}),this}}(jQuery,window,document);
-
-// textarea autosize default
-	$(function () {
-		'use strict';
-
-		$('.textarea-autosize').textareaAutoSize();
-	});

+ 0 - 12
public/theme/tabler/assets/js/header.js

@@ -1,12 +0,0 @@
-// header waterfall
-	$(function () {
-		'use strict';
-
-		$('.header-waterfall').each(function () {
-			$(this).affix({
-				offset: {
-					top: 1
-				}
-			});
-		});
-	});

+ 0 - 200
public/theme/tabler/assets/js/menu.js

@@ -1,200 +0,0 @@
-// menu
-	(function ($) {
-		'use strict';
-
-		var Menu = function (element, options) {
-			this.ignoreBackdropClick = false;
-			this.isShown             = null;
-			this.options             = options;
-			this.originalBodyPad     = null;
-			this.scrollbarWidth      = 0;
-			this.$backdrop           = null;
-			this.$body               = $(document.body);
-			this.$element            = $(element);
-			this.$dialog             = this.$element.find('.menu-scroll');
-		};
-
-		if (!$.fn.modal) {
-			throw new Error('Menu requires Bootstrap modal.js');
-		};
-
-		Menu.DEFAULTS = $.extend({}, $.fn.modal.Constructor.DEFAULTS, {});
-		Menu.TRANSITION_DURATION = 300;
-		Menu.TRANSITION_DURATION_BACKDROP = 150;
-
-		Menu.prototype = $.extend({}, $.fn.modal.Constructor.prototype);
-
-		Menu.prototype.backdrop = function (callback) {
-			var that = this;
-
-			if (this.isShown && this.options.backdrop) {
-				var doAnimate = $.support.transition;
-
-				this.$backdrop = $(document.createElement('div')).addClass('menu-backdrop').appendTo(this.$body);
-
-				this.$element.on('click.dismiss.bs.menu', $.proxy(function (e) {
-					if (this.ignoreBackdropClick) {
-						this.ignoreBackdropClick = false;
-						return;
-					};
-
-					if (e.target !== e.currentTarget) {
-						return;
-					};
-
-					this.options.backdrop == 'static' ? this.$element[0].focus() : this.hide();
-				}, this));
-
-				if (doAnimate) {
-					this.$backdrop[0].offsetWidth;
-				};
-
-				this.$backdrop.addClass('in');
-
-				if (!callback) {
-					return;
-				};
-
-				doAnimate ? this.$backdrop.one('bsTransitionEnd', callback).emulateTransitionEnd(Menu.TRANSITION_DURATION_BACKDROP) : callback();
-			} else if (!this.isShown && this.$backdrop) {
-				this.$backdrop.removeClass('in');
-
-				var callbackRemove = function () {
-					that.removeBackdrop();
-					callback && callback();
-				};
-
-				$.support.transition ? this.$backdrop.one('bsTransitionEnd', callbackRemove).emulateTransitionEnd(Menu.TRANSITION_DURATION_BACKDROP) : callbackRemove();
-			} else if (callback) {
-				callback();
-			};
-		};
-
-		Menu.prototype.hide = function (e) {
-			if (e) e.preventDefault();
-
-			e = $.Event('hide.bs.menu');
-
-			this.$element.trigger(e);
-
-			if (!this.isShown || e.isDefaultPrevented()) {
-				return;
-			};
-
-			this.isShown = false;
-
-			this.escape();
-
-			$(document).off('focusin.bs.modal');
-
-			this.$element.removeClass('in').off('click.dismiss.bs.menu').off('mouseup.dismiss.bs.menu');
-
-			this.$dialog.off('mousedown.dismiss.bs.menu');
-
-			$.support.transition ? this.$element.one('bsTransitionEnd', $.proxy(this.hideModal, this)).emulateTransitionEnd(Menu.TRANSITION_DURATION) : this.hideModal();
-		};
-
-		Menu.prototype.hideModal = function () {
-			var that = this;
-
-			this.$element.hide();
-
-			this.backdrop(function () {
-				that.$element.trigger('hidden.bs.menu');
-			});
-		};
-
-		Menu.prototype.show = function (_relatedTarget) {
-			var that = this;
-			var e    = $.Event('show.bs.menu', { relatedTarget: _relatedTarget });
-
-			this.$element.trigger(e);
-
-			if (this.isShown || e.isDefaultPrevented()) {
-				return;
-			};
-
-			this.isShown = true;
-
-			this.escape();
-
-			this.$element.on('click.dismiss.bs.menu', '[data-dismiss="menu"]', $.proxy(this.hide, this));
-
-			this.$dialog.on('mousedown.dismiss.bs.menu', function () {
-				that.$element.one('mouseup.dismiss.bs.menu', function (e) {
-					if ($(e.target).is(that.$element)) {
-						that.ignoreBackdropClick = true;
-					};
-				});
-			});
-
-			this.backdrop(function () {
-				var transition = $.support.transition;
-
-				if (!that.$element.parent().length) {
-					that.$element.appendTo(that.$body);
-				};
-
-				that.$element.show();
-
-				if (transition) {
-					that.$element[0].offsetWidth;
-				};
-
-				that.$element.addClass('in');
-
-				that.enforceFocus();
-
-				var e = $.Event('shown.bs.menu', { relatedTarget: _relatedTarget });
-
-				transition ? that.$dialog.one('bsTransitionEnd', function () {
-					that.$element.trigger('focus').trigger(e);
-				}).emulateTransitionEnd(Menu.TRANSITION_DURATION) : that.$element.trigger('focus').trigger(e);
-			});
-		};
-
-		function Plugin (option, _relatedTarget) {
-			return this.each(function () {
-				var $this   = $(this);
-				var data    = $this.data('bs.menu');
-				var options = $.extend({}, Menu.DEFAULTS, $this.data(), typeof option == 'object' && option);
-
-				if (!data) $this.data('bs.menu', (data = new Menu(this, options)));
-				if (typeof option == 'string') data[option](_relatedTarget);
-				else if (options.show) data.show(_relatedTarget);
-			});
-		};
-
-		var old = $.fn.menu;
-
-		$.fn.menu             = Plugin;
-		$.fn.menu.Constructor = Menu;
-
-		$.fn.menu.noConflict = function () {
-			$.fn.menu = old;
-			return this;
-		};
-
-		$(document).on('click.bs.menu.data-api', '[data-toggle="menu"]', function (e) {
-			var $this   = $(this);
-			var href    = $this.attr('href');
-			var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, '')));
-			var option  = $target.data('bs.menu') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
-
-			if ($this.is('a')) e.preventDefault();
-
-			$target.one('show.bs.menu', function (showEvent) {
-				if (showEvent.isDefaultPrevented()) {
-					return;
-				} else {
-					$target.attr('tabindex', '-1');
-				};
-
-				$target.one('hidden.bs.menu', function () {
-					$this.is(':visible') && $this.trigger('focus');
-				});
-			});
-
-			Plugin.call($target, option, this);
-		});
-	}(jQuery));

+ 0 - 12
public/theme/tabler/assets/js/modal.js

@@ -1,12 +0,0 @@
-// modale dialog vertical alignment
-	$(function () {
-		'use strict';
-
-		$(document).on('hidden.bs.modal', '.modal-va-middle', function () {
-			$(this).removeClass('modal-va-middle-show');
-		});
-
-		$(document).on('show.bs.modal', '.modal-va-middle', function () {
-			$(this).addClass('modal-va-middle-show');
-		});
-	});

Різницю між файлами не показано, бо вона завелика
+ 0 - 4
public/theme/tabler/assets/js/picker.js


+ 0 - 116
public/theme/tabler/assets/js/snackbar.js

@@ -1,116 +0,0 @@
-// snackbar
-	(function ($) {
-		'use strict';
-
-		var Snackbar = function (options) {
-			this.options  = options;
-			this.$element = $('<div class="snackbar-inner">' + this.options.content + '</div>');
-		};
-
-		Snackbar.DEFAULTS = {
-			alive: 6000,
-			content: '&nbsp;',
-			hide: function () {},
-			show: function () {}
-		};
-
-		Snackbar.prototype.fbtn = function (margin) {
-			if ($(window).width() < 768 && $('.fbtn-container').length) {
-				var str = 'translateY(-' + margin + 'px)';
-				$('.fbtn-container').css({
-					'-webkit-transform': str,
-					'transform': str
-				});
-			};
-		};
-
-		Snackbar.prototype.hide = function () {
-			var that = this;
-
-			this.$element.removeClass('in');
-
-			clearTimeout(this.$element.data('timer'));
-
-			if ($.support.transition) {
-				this.$element.one('bsTransitionEnd', function () {
-					that.options.hide(that.options);
-					that.$element.remove();
-				});
-			} else {
-				that.options.hide(that.options);
-				that.$element.remove();
-			}
-
-			this.fbtn('0');
-		};
-
-		Snackbar.prototype.show = function () {
-			var that = this;
-
-			if (!$('.snackbar').length) {
-				$(document.body).append('<div class="snackbar"></div>');
-			};
-
-			this.$element.appendTo('.snackbar').show().addClass(function () {
-				that.$element.on('click', '[data-dismiss="snackbar"]', function () {
-					that.hide();
-				});
-
-				that.$element.data('timer', setTimeout(function () {
-					that.hide();
-				}, that.options.alive));
-
-				that.$element.on('mouseenter', function () {
-					clearTimeout(that.$element.data('timer'));
-				}).on('mouseleave', function () {
-					that.$element.data('timer', setTimeout(function () {
-						that.hide();
-					}, that.options.alive));
-				});
-
-				that.options.show(that.options);
-
-				return 'in';
-			});
-
-			this.fbtn(this.$element.outerHeight());
-		};
-
-		function Plugin (option) {
-			return this.each(function () {
-				var $this    = $(document.body);
-				var data     = $this.data('bs.snackbar');
-				var options  = $.extend({}, Snackbar.DEFAULTS, option);
-
-				if (!data) {
-					$this.data('bs.snackbar', (data = new Snackbar(options)));
-					data.show();
-				} else if ($('.snackbar-inner').length && !$('.snackbar-inner.old').length) {
-					$('.snackbar-inner.in').addClass('old')
-					data.hide();
-					if ($.support.transition) {
-						$(document).one('bsTransitionEnd', '.snackbar-inner.old', function () {
-							$this.data('bs.snackbar', (data = new Snackbar(options)));
-							data.show();
-						});
-					} else {
-						$this.data('bs.snackbar', (data = new Snackbar(options)));
-						data.show();
-					};
-				} else if (!$('.snackbar-inner').length) {
-					$this.data('bs.snackbar', (data = new Snackbar(options)));
-					data.show();
-				};
-			});
-		};
-
-		var old = $.fn.snackbar;
-
-		$.fn.snackbar             = Plugin;
-		$.fn.snackbar.Constructor = Snackbar;
-
-		$.fn.snackbar.noConflict = function () {
-			$.fn.snackbar = old;
-			return this;
-		};
-	}(jQuery));

+ 0 - 51
public/theme/tabler/assets/js/tab.js

@@ -1,51 +0,0 @@
-// tab switch
-	(function ($) {
-		'use strict';
-
-		$.fn.tabSwitch = function (oldTab) {
-			var $this = $(this),
-			    $thisNav = $this.closest('.tab-nav'),
-			    $thisNavIndicator = $('.tab-nav-indicator', $thisNav),
-			    thisLeft = $this.offset().left,
-			    thisNavLeft = $thisNav.offset().left,
-			    thisNavWidth = $thisNav.outerWidth();
-
-			if (oldTab !== undefined && oldTab[0] !== undefined) {
-				var oldTabLeft = oldTab.offset().left;
-
-				$thisNavIndicator.css({
-					left: (oldTabLeft - thisNavLeft),
-					right: (thisNavLeft + thisNavWidth - oldTabLeft - oldTab.outerWidth())
-				});
-
-				if (oldTab.offset().left > thisLeft) {
-					$thisNavIndicator.addClass('reverse');
-
-					$thisNavIndicator.one('webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend', function () {
-						$thisNavIndicator.removeClass('reverse');
-					});
-				};
-			};
-
-			$thisNavIndicator.addClass('animate').css({
-				left: (thisLeft - thisNavLeft),
-				right: (thisNavLeft + thisNavWidth - thisLeft - $this.outerWidth())
-			}).one('webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend', function () {
-				$thisNavIndicator.removeClass('animate');
-			});
-
-			return this;
-		}
-	})(jQuery);
-
-	$(function () {
-		'use strict';
-
-		$('.tab-nav').each(function () {
-			$(this).append('<div class="tab-nav-indicator"></div>');
-		});
-
-		$(document).on('show.bs.tab', '.tab-nav a[data-toggle="tab"]', function (e) {
-			$(e.target).tabSwitch($(e.relatedTarget));
-		});
-	});

+ 0 - 181
public/theme/tabler/assets/js/tile.js

@@ -1,181 +0,0 @@
-// tile
-	(function ($) {
-		'use strict';
-
-		var Tile = function (element, options) {
-			this.options       = $.extend({}, Tile.DEFAULTS, options);
-			this.transitioning = null;
-			this.$element      = $(element);
-
-			if (this.options.parent) {
-				this.$parent = this.getParent();
-			};
-
-			if (this.options.toggle) {
-				this.toggle();
-			};
-		};
-
-		if (!$.fn.collapse) {
-			throw new Error('Menu requires Bootstrap collapse.js');
-		};
-
-		Tile.DEFAULTS = {
-			keyboard: true,
-			toggle: true
-		};
-		Tile.TRANSITION_DURATION = 150;
-
-		Tile.prototype = $.extend({}, $.fn.collapse.Constructor.prototype);
-
-		Tile.prototype.escape = function () {
-			if (this.$element.hasClass('in') && this.options.keyboard) {
-				$(document).on('keydown.dismiss.bs.tile', $.proxy(function (e) {
-					e.which == 27 && this.hide();
-				}, this));
-			} else if (!this.$element.hasClass('in')) {
-				this.$element.off('keydown.dismiss.bs.tile');
-			};
-		};
-
-		Tile.prototype.hide = function () {
-			if (this.transitioning || !this.$element.hasClass('in')) {
-				return;
-			};
-
-			var startEvent = $.Event('hide.bs.tile');
-
-			this.$element.trigger(startEvent);
-
-			if (startEvent.isDefaultPrevented()) {
-				return;
-			};
-
-			var dimension = this.dimension();
-
-			this.$element[dimension](this.$element[dimension]())[0].offsetHeight;
-
-			this.$element.addClass('collapsing').removeClass('collapse in');
-
-			this.$element.closest('.tile-collapse').removeClass('active');
-
-			this.transitioning = 1
-
-			var complete = function () {
-				this.transitioning = 0;
-				this.$element.removeClass('collapsing').addClass('collapse').trigger('hidden.bs.tile');
-				this.escape();
-			};
-
-			if (!$.support.transition) {
-				return complete.call(this);
-			};
-
-			this.$element[dimension](0).one('bsTransitionEnd', $.proxy(complete, this)).emulateTransitionEnd(Tile.TRANSITION_DURATION);
-		};
-
-		Tile.prototype.show = function () {
-			if (this.transitioning || this.$element.hasClass('in')) {
-				return;
-			};
-
-			var actives = this.$parent && this.$parent.find('.tile-collapse').children('.in, .collapsing');
-			var activesData;
-
-			if (actives && actives.length) {
-				activesData = actives.data('bs.tile');
-				if (activesData && activesData.transitioning) {
-					return;
-				};
-			};
-
-			var startEvent = $.Event('show.bs.tile');
-
-			this.$element.trigger(startEvent);
-
-			if (startEvent.isDefaultPrevented()) {
-				return;
-			};
-
-			if (actives && actives.length) {
-				Plugin.call(actives, 'hide');
-				activesData || actives.data('bs.tile', null);
-			};
-
-			var dimension = this.dimension();
-
-			this.$element.removeClass('collapse').addClass('collapsing')[dimension](0);
-
-			this.$element.closest('.tile-collapse').addClass('active');
-
-			this.transitioning = 1;
-
-			var complete = function () {
-				this.$element.removeClass('collapsing').addClass('collapse in')[dimension]('');
-				this.transitioning = 0;
-				this.$element.trigger('shown.bs.tile');
-				this.escape();
-			};
-
-			if (!$.support.transition) {
-				return complete.call(this);
-			};
-
-			var scrollSize = $.camelCase(['scroll', dimension].join('-'));
-
-			this.$element.one('bsTransitionEnd', $.proxy(complete, this)).emulateTransitionEnd(Tile.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]);
-		};
-
-		function getTargetFromTrigger($trigger) {
-			var href;
-			var target = $trigger.attr('data-target') || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '');
-
-			return $(target);
-		};
-
-		function Plugin(option) {
-			return this.each(function () {
-				var $this   = $(this);
-				var data    = $this.data('bs.tile');
-				var options = $.extend({}, Tile.DEFAULTS, $this.data(), typeof option == 'object' && option);
-
-				if (!data && options.toggle && /show|hide/.test(option)) {
-					options.toggle = false;
-				};
-
-				if (!data) {
-					$this.data('bs.tile', (data = new Tile(this, options)));
-				};
-
-				if (typeof option == 'string') {
-					data[option]();
-				};
-			})
-		};
-
-		var old = $.fn.tile;
-
-		$.fn.tile             = Plugin;
-		$.fn.tile.Constructor = Tile;
-
-		$.fn.tile.noConflict = function () {
-			$.fn.tile = old;
-			return this;
-		};
-
-		$(document).on('click.bs.tile.data-api', '[data-toggle="tile"]', function (e) {
-			var $this = $(this);
-
-			if (!$(e.target).is('[data-ignore="tile"], [data-ignore="tile"] *')) {
-				if (!$this.attr('data-target')) {
-					e.preventDefault();
-				};
-
-				var $target = getTargetFromTrigger($this);
-				var data    = $target.data('bs.tile');
-				var option  = data ? 'toggle' : $this.data();
-
-				Plugin.call($target, option);
-			};
-		});
-	}(jQuery));

Різницю між файлами не показано, бо вона завелика
+ 0 - 5
public/theme/tabler/assets/js/wave.js


BIN
public/theme/tabler/css/images/bg/geometry.jpg


BIN
public/theme/tabler/css/images/bg/streak.jpg


+ 0 - 1
public/theme/tabler/css/user.css

@@ -337,7 +337,6 @@ a.btn-dl:visited {
   border-radius: 16px;
   top: 0;
   left: 0;
-  background: url(/theme/tabler/images/users/trafficbar.png) 0 0;
   animation: sparkle 1500ms linear infinite;
   animation: sparkle 1500ms linear infinite;
   animation: sparkle 1500ms linear infinite;

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
public/theme/tabler/css/user.min.css


BIN
public/theme/tabler/images/users/trafficbar.png


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
public/theme/tabler/js/base.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
public/theme/tabler/js/base.min.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
public/theme/tabler/js/jquery.qrcode.min.js


+ 1 - 1
resources/views/tabler/admin/announcement/index.tpl

@@ -119,7 +119,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 3 - 3
resources/views/tabler/admin/coupon.tpl

@@ -195,7 +195,7 @@
                     }
                 }
             })
-        };
+        }
 
         function deleteCoupon(coupon_id) {
             $('#notice-message').text('确定删除此优惠码?');
@@ -217,7 +217,7 @@
                     }
                 })
             });
-        };
+        }
 
         function disableCoupon(coupon_id) {
             $('#notice-message').text('确定禁用此优惠码?');
@@ -239,7 +239,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 1 - 1
resources/views/tabler/admin/detect.tpl

@@ -186,7 +186,7 @@
                     }
                 })
             });
-        };
+        }
 
         function loadTable() {
             table;

+ 0 - 17
resources/views/tabler/admin/footer.tpl

@@ -1,17 +0,0 @@
-<footer class="ui-footer">
-    <div class="container">
-        &copy;{date("Y")} {$config['appName']} | Powered by <a href="/staff">SSPANEL</a>
-        {if $config['enable_analytics_code'] === true}{include file='analytics.tpl'}{/if}
-    </div>
-</footer>
-
-<!-- js -->
-<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/clipboard.min.js"></script>
-<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/jquery.validate.min.js"></script>
-<script src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
-<script src="//cdn.datatables.net/1.10.19/js/dataTables.material.min.js"></script>
-<script src="/theme/tabler/js/base.min.js"></script>
-<script src="/theme/tabler/js/project.min.js"></script>
-
-</body>
-</html>

+ 2 - 2
resources/views/tabler/admin/giftcard.tpl

@@ -175,7 +175,7 @@
                     }
                 }
             })
-        };
+        }
 
         function deleteGiftCard(giftcard_id) {
             $('#notice-message').text('确定删除此礼品卡?');
@@ -197,7 +197,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 0 - 0
resources/views/tabler/admin/log/detect_log.tpl → resources/views/tabler/admin/log/detect.tpl


+ 0 - 114
resources/views/tabler/admin/main.tpl

@@ -1,114 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-cn">
-<head>
-    <meta charset="UTF-8">
-    <meta content="IE=edge" http-equiv="X-UA-Compatible">
-    <meta content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width" name="viewport">
-    <meta name="theme-color" content="#4285f4">
-    <title>{$config['appName']}</title>
-    <!-- css -->
-    <link href="/theme/tabler/css/base.min.css" rel="stylesheet">
-    <link href="/theme/tabler/css/project.min.css" rel="stylesheet">
-    <link href="//cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css" rel="stylesheet">
-    <link href="//cdn.jsdelivr.net/npm/[email protected]/material.min.css" rel="stylesheet">
-    <link href="//cdn.datatables.net/1.12.1/css/dataTables.material.min.css" rel="stylesheet">
-    <!-- js -->
-    <script src="//cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
-    <!-- ... -->
-    <style>
-        body {
-            position: relative;
-        }
-
-        .table-responsive {
-            background: white;
-        }
-
-        .dropdown-menu.dropdown-menu-right a {
-            color: #212121;
-        }
-
-        a[href='#ui_menu'] {
-            color: #212121;
-        }
-
-        #custom_config {
-            height: 500px;
-        }
-    </style>
-</head>
-
-<body class="page-brand">
-<header class="header header-red header-transparent header-waterfall ui-header">
-    <ul class="nav nav-list pull-left">
-        <div>
-            <a data-toggle="menu" href="#ui_menu">
-                <span class="mdi mdi-menu icon-lg"></span>
-            </a>
-        </div>
-    </ul>
-    <ul class="nav nav-list pull-right">
-        <div class="dropdown margin-right">
-            <a class="dropdown-toggle padding-left-no padding-right-no" data-toggle="dropdown">
-                <span class="access-hide">{$user->user_name}</span>
-                <span class="avatar avatar-sm"><img src="{$user->gravatar}"></span>
-            </a>
-            <ul class="dropdown-menu dropdown-menu-right">
-                <li>
-                    <a class="waves-attach" href="/user/logout"><span
-                                class="mdi mdi-exit-to-app icon-lg margin-right"></span>登出</a>
-                </li>
-            </ul>
-        </div>
-    </ul>
-</header>
-<nav aria-hidden="true" class="menu menu-left nav-drawer nav-drawer-md" id="ui_menu" tabindex="-1">
-    <div class="menu-scroll">
-        <div class="menu-content">
-            <a class="menu-logo" href="/">&nbsp;管理面板</a>
-            <ul class="nav">
-                <li>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_me">我的</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_me">
-                        <li><a href="/admin"><i class="mdi mdi-eye icon-lg"></i>&nbsp;系统概览</a></li>
-                        <li><a href="/admin/announcement"><i class="mdi mdi-bullhorn-variant icon-lg"></i>&nbsp;公告管理</a></li>
-                        <li><a href="/admin/ticket"><i class="mdi mdi-comment-question icon-lg"></i>&nbsp;工单管理</a></li>
-                    </ul>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_node">节点</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_node">
-                        <li><a href="/admin/node"><i class="mdi mdi-server icon-lg"></i>&nbsp;节点列表</a></li>
-                    </ul>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_user">用户</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_user">
-                        <li><a href="/admin/user"><i class="mdi mdi-account-group icon-lg"></i>&nbsp;用户列表</a></li>
-                        <li><a href="/admin/invite"><i class="mdi mdi-account-multiple-plus icon-lg"></i>&nbsp;邀请与返利</a></li>
-                        <li><a href="/admin/subscribe"><i class="mdi mdi-file-find icon-lg"></i>&nbsp;订阅记录</a></li>
-                        <li><a href="/admin/login"><i class="mdi mdi-text-account icon-lg"></i>&nbsp;登录记录</a></li>
-                        <li><a href="/admin/trafficlog"><i class="mdi mdi-swap-vertical icon-lg"></i>&nbsp;流量记录</a></li>
-                        <li><a href="/admin/alive"><i class="mdi mdi-account-badge icon-lg"></i>&nbsp;在线IP</a></li>
-                    </ul>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_config">配置</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_config">
-                        <li><a href="/admin/setting"><i class="mdi mdi-cog icon-lg"></i>&nbsp;设置中心</a></li>
-                    </ul>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_detect">审计</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_detect">
-                        <li><a href="/admin/detect"><i class="mdi mdi-account-filter icon-lg"></i>&nbsp;审计规则</a></li>
-                        <li><a href="/admin/detect/log"><i class="mdi mdi-calendar-filter icon-lg"></i>&nbsp;审计记录</a></li>
-                        <li><a href="/admin/detect/ban"><i class="mdi mdi-account-cancel icon-lg"></i>&nbsp;审计封禁</a></li>
-                    </ul>
-                    <a class="waves-attach" data-toggle="collapse" href="#ui_menu_trade">财务</a>
-                    <ul class="menu-collapse collapse in" id="ui_menu_trade">
-                        <li><a href="/admin/code">
-                                <i class="mdi mdi-currency-usd icon-lg"></i>
-                                &nbsp;充值记录</a>
-                        </li>
-                        <li><a href="/admin/shop"><i class="mdi mdi-shopping icon-lg"></i>&nbsp;商品</a></li>
-                        <li><a href="/admin/coupon"><i class="mdi mdi-code-tags icon-lg"></i>&nbsp;优惠码</a></li>
-                        <li><a href="/admin/bought"><i class="mdi mdi-shopping-search icon-lg"></i>&nbsp;购买记录</a></li>
-                    </ul>
-                <li><a href="/user"><i class="mdi mdi-account icon-lg"></i>&nbsp;用户中心</a></li>
-            </ul>
-        </div>
-    </div>
-</nav>

+ 2 - 2
resources/views/tabler/admin/node/index.tpl

@@ -121,7 +121,7 @@
                     }
                 })
             });
-        };
+        }
 
         function copyNode(node_id) {
             $('#notice-message').text('确定复制此节点?');
@@ -143,7 +143,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 2 - 2
resources/views/tabler/admin/order/index.tpl

@@ -111,7 +111,7 @@
                     }
                 })
             });
-        };
+        }
 
         function cancelOrder(order_id) {
             $('#notice-message').text('确定取消此订单?');
@@ -133,7 +133,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 2 - 2
resources/views/tabler/admin/product/index.tpl

@@ -119,7 +119,7 @@
                     }
                 })
             });
-        };
+        }
 
         function copyProduct(product_id) {
             $('#notice-message').text('确定复制此产品?');
@@ -141,7 +141,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 0 - 90
resources/views/tabler/admin/shop/bought.tpl

@@ -1,90 +0,0 @@
-{include file='admin/main.tpl'}
-
-<main class="content">
-    <div class="content-header ui-content-header">
-        <div class="container">
-            <h1 class="content-heading">购买记录</h1>
-        </div>
-    </div>
-    <div class="container">
-        <div class="col-lg-12 col-sm-12">
-            <section class="content-inner margin-top-no">
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <p>系统中所有购买记录。</p>
-                            <p>显示表项:
-                                {include file='table/checkbox.tpl'}
-                            </p>
-                        </div>
-                    </div>
-                </div>
-                <div class="table-responsive">
-                    {include file='table/table.tpl'}
-                </div>
-                <div aria-hidden="true" class="modal modal-va-middle fade" id="delete_modal" role="dialog"
-                     tabindex="-1">
-                    <div class="modal-dialog modal-xs">
-                        <div class="modal-content">
-                            <div class="modal-heading">
-                                <a class="modal-close" data-dismiss="modal">×</a>
-                                <h2 class="modal-title">确认要退订?</h2>
-                            </div>
-                            <div class="modal-inner">
-                                <p>请您确认。</p>
-                            </div>
-                            <div class="modal-footer">
-                                <p class="text-right">
-                                    <button class="btn btn-flat btn-brand-accent waves-attach waves-effect"
-                                            data-dismiss="modal" type="button">取消
-                                    </button>
-                                    <button class="btn btn-flat btn-brand-accent waves-attach" data-dismiss="modal"
-                                            id="delete_input" type="button">确定
-                                    </button>
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                {include file='dialog.tpl'}
-        </div>
-    </div>
-</main>
-
-{include file='admin/footer.tpl'}
-
-<script>
-    function delete_modal_show(id) {
-        deleteid = id;
-        $("#delete_modal").modal();
-    }
-    {include file='table/js_1.tpl'}
-    window.addEventListener('load', () => {
-        {include file='table/js_2.tpl'}
-        function delete_id() {
-            $.ajax({
-                type: "DELETE",
-                url: "/admin/bought",
-                dataType: "json",
-                data: {
-                    id: deleteid
-                },
-                success: data => {
-                    if (data.ret) {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                        $$.getElementById(`row_delete_${ldelim}deleteid{rdelim}`).setAttribute('disabled', 'true')
-                    } else {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                    }
-                },
-                error: jqXHR => {
-                    $("#result").modal();
-                    $$.getElementById('msg').innerHTML = `${ldelim}data.msg{rdelim} 发生错误了`;
-                }
-            });
-        }
-        $$.getElementById('delete_input').addEventListener('click', delete_id);
-    })
-</script>

+ 0 - 238
resources/views/tabler/admin/shop/create.tpl

@@ -1,238 +0,0 @@
-{include file='admin/main.tpl'}
-
-<main class="content">
-    <div class="content-header ui-content-header">
-        <div class="container">
-            <h1 class="content-heading">添加商品</h1>
-        </div>
-    </div>
-    <div class="container">
-        <div class="col-lg-12 col-sm-12">
-            <section class="content-inner margin-top-no">
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="name">名称</label>
-                                <input class="form-control maxwidth-edit" id="name" type="text">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="price">价格</label>
-                                <input class="form-control maxwidth-edit" id="price" type="text">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="auto_renew">自动续订天数</label>
-                                <input class="form-control maxwidth-edit" id="auto_renew" type="text" value="0">
-                                <p class="form-control-guide"><i class="mdi mdi-information"></i>0为不允许自动续订,其他为到了那么多天之后就会自动从用户的账户上划钱抵扣
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="bandwidth">流量(GB)</label>
-                                <input class="form-control maxwidth-edit" id="bandwidth" type="text">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <div class="checkbox switch">
-                                    <label for="auto_reset_bandwidth">
-                                        <input class="access-hide" id="auto_reset_bandwidth" type="checkbox"><span
-                                                class="switch-toggle"></span>续费时自动重置用户流量为上面这个流量值
-                                    </label>
-                                </div>
-                            </div>
-
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="traffic-package-min">最低可购买用户等级</label>
-                                <input class="form-control maxwidth-edit" id="traffic-package-min" type="text">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="traffic-package-max">最高可购买用户等级</label>
-                                <input class="form-control maxwidth-edit" id="traffic-package-max" type="text">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <div class="checkbox switch">
-                                    <label for="traffic-package-enable">
-                                        <input class="access-hide" id="traffic-package-enable" type="checkbox"><span
-                                                class="switch-toggle"></span>是否设置此商品为流量叠加包
-                                    </label>
-                                    <p class="form-control-guide">
-                                        <i class="mdi mdi-information"></i>
-                                        设置为流量叠加包后除购买时获得流量外的设置无效
-                                    </p>
-                                </div>
-                            </div>
-
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="expire">账户有效期天数</label>
-                                <input class="form-control maxwidth-edit" id="expire" type="text" value="0">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="class">等级</label>
-                                <input class="form-control maxwidth-edit" id="class" type="text" value="0">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="class_expire">等级有效期天数</label>
-                                <input class="form-control maxwidth-edit" id="class_expire" type="text" value="0">
-                            </div>
-                            <p class="form-control-guide"><i class="mdi mdi-information"></i>如需使用等级功能,请同时填写【等级】和【等级有效期天数】这两个项目</p>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset_exp">多少天内</label>
-                                <input class="form-control maxwidth-edit" id="reset_exp" type="number" value="0">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset">每多少天</label>
-                                <input class="form-control maxwidth-edit" id="reset" type="number" value="0">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset_value">重置流量为多少G</label>
-                                <input class="form-control maxwidth-edit" id="reset_value" type="number" value="0">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="speedlimit">端口限速</label>
-                                <input class="form-control maxwidth-edit" id="speedlimit" type="number" value="0">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="connector">IP限制</label>
-                                <input class="form-control maxwidth-edit" id="connector" type="number" value="0">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="content_extra">服务支持</label>
-                                <input class="form-control maxwidth-edit" id="content_extra" type="text" value="">
-                                <p class="form-control-guide"><i class="mdi mdi-information"></i>例:<code>check-全球节点分布;clear-快速客服响应</code>,减号左边为icon代号右边为文字,以;隔开
-                                </p>
-                                <p class="form-control-guide">icon代号参阅:<a
-                                            href="https://materialdesignicons.com/">Material Design Icons</a>
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group">
-                                <div class="row">
-                                    <div class="col-md-10 col-md-push-1">
-                                        <button id="submit" type="submit"
-                                                class="btn btn-block btn-brand waves-attach waves-light">添加
-                                        </button>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                {include file='dialog.tpl'}
-        </div>
-    </div>
-</main>
-
-{include file='admin/footer.tpl'}
-
-<script>
-    window.addEventListener('load', () => {
-        function submit() {
-            if ($$.getElementById('auto_reset_bandwidth').checked) {
-                var auto_reset_bandwidth = 1;
-            } else {
-                var auto_reset_bandwidth = 0;
-            }
-            let contentExtra = $$getValue('content_extra');
-            if (contentExtra === '') {
-                contentExtra = 'check-全球节点分布;check-快速客服响应;check-全平台客户端';
-            }
-            let data = {
-                name: $$getValue('name'),
-                auto_reset_bandwidth,
-                price: $$getValue('price'),
-                auto_renew: $$getValue('auto_renew'),
-                bandwidth: $$getValue('bandwidth'),
-                speedlimit: $$getValue('speedlimit'),
-                connector: $$getValue('connector'),
-                expire: $$getValue('expire'),
-                class: $$getValue('class'),
-                class_expire: $$getValue('class_expire'),
-                reset: $$getValue('reset'),
-                reset_value: $$getValue('reset_value'),
-                reset_exp: $$getValue('reset_exp'),
-                content_extra: contentExtra,
-            }
-            if ($$.getElementById('traffic-package-enable').checked) {
-                data.traffic_package = {
-                    class: {
-                        min: $$getValue('traffic-package-min'),
-                        max: $$getValue('traffic-package-max')
-                    }
-                }
-            }
-            $.ajax({
-                type: "POST",
-                url: "/admin/shop",
-                dataType: "json",
-                data,
-                success: data => {
-                    if (data.ret) {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                        window.setTimeout("location.href=top.document.referrer", {$config['jump_delay']});
-                    } else {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                    }
-                },
-                error: jqXHR => {
-                    $("#result").modal();
-                    $$.getElementById('msg').innerHTML = `发生错误:${
-                            jqXHR.status
-                            }`;
-                }
-            });
-        }
-        $("html").keydown(event => {
-            if (event.keyCode == 13) {
-                submit();
-            }
-        });
-        $$.getElementById('submit').addEventListener('click', submit);
-    })
-</script>

+ 0 - 251
resources/views/tabler/admin/shop/edit.tpl

@@ -1,251 +0,0 @@
-{include file='admin/main.tpl'}
-
-<main class="content">
-    <div class="content-header ui-content-header">
-        <div class="container">
-            <h1 class="content-heading">编辑商品</h1>
-        </div>
-    </div>
-    <div class="container">
-        <div class="col-lg-12 col-sm-12">
-            <section class="content-inner margin-top-no">
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="name">名称</label>
-                                <input class="form-control maxwidth-edit" id="name" type="text" value="{$shop->name}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="price">价格</label>
-                                <input class="form-control maxwidth-edit" id="price" type="text" value="{$shop->price}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="auto_renew">自动续订天数</label>
-                                <input class="form-control maxwidth-edit" id="auto_renew" type="text"
-                                       value="{$shop->auto_renew}">
-                                <p class="form-control-guide"><i class="mdi mdi-information"></i>0为不允许自动续订,其他为到了那么多天之后就会自动从用户的账户上划钱抵扣
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="bandwidth">流量(GB)</label>
-                                <input class="form-control maxwidth-edit" id="bandwidth" type="text"
-                                       value="{$shop->bandwidth()}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <div class="checkbox switch">
-                                    <label for="auto_reset_bandwidth">
-                                        <input {if $shop->auto_reset_bandwidth==1}checked{/if} class="access-hide"
-                                               id="auto_reset_bandwidth" type="checkbox"><span
-                                                class="switch-toggle"></span>续费时自动重置用户流量为上面这个流量值
-                                    </label>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="traffic-package-min">最低可购买用户等级</label>
-                                <input class="form-control maxwidth-edit" id="traffic-package-min" type="text"
-                                value="{if $shop->trafficPackage()}{$shop->content['traffic_package']['class']['min']}{else}0{/if}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="traffic-package-max">最高可购买用户等级</label>
-                                <input class="form-control maxwidth-edit" id="traffic-package-max" type="text"
-                                value="{if $shop->trafficPackage()}{$shop->content['traffic_package']['class']['max']}{else}0{/if}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <div class="checkbox switch">
-                                    <label for="traffic-package-enable">
-                                        <input {if $shop->trafficPackage()}checked{/if} class="access-hide" id="traffic-package-enable" type="checkbox">
-                                        <span class="switch-toggle"></span>是否设置此商品为流量叠加包
-                                    </label>
-                                    <p class="form-control-guide">
-                                        <i class="mdi mdi-information"></i>
-                                        设置为流量叠加包后除购买时获得流量外的设置无效
-                                    </p>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="expire">账户有效期天数</label>
-                                <input class="form-control maxwidth-edit" id="expire" type="text"
-                                       value="{$shop->expire()}">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="class">等级</label>
-                                <input class="form-control maxwidth-edit" id="class" type="text"
-                                       value="{$shop->userClass()}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="class_expire">等级有效期天数</label>
-                                <input class="form-control maxwidth-edit" id="class_expire" type="text"
-                                       value="{$shop->classExpire()}">
-                            </div>
-                            <p class="form-control-guide"><i class="mdi mdi-information"></i>如需使用等级功能,请同时填写【等级】和【等级有效期天数】这两个项目</p>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset_exp">多少天内</label>
-                                <input class="form-control maxwidth-edit" id="reset_exp" type="number"
-                                       value="{$shop->resetExp()}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset">每多少天</label>
-                                <input class="form-control maxwidth-edit" id="reset" type="number"
-                                       value="{$shop->reset()}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="reset_value">重置流量为多少G</label>
-                                <input class="form-control maxwidth-edit" id="reset_value" type="number"
-                                       value="{$shop->resetValue()}">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="speedlimit">端口限速</label>
-                                <input class="form-control maxwidth-edit" id="speedlimit" type="number"
-                                       value="{$shop->speedlimit()}">
-                            </div>
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="connector">IP限制</label>
-                                <input class="form-control maxwidth-edit" id="connector" type="number"
-                                       value="{$shop->connector()}">
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <div class="form-group form-group-label">
-                                <label class="floating-label" for="content_extra">服务支持</label>
-                                <input class="form-control maxwidth-edit" id="content_extra" type="text"
-                                       value="{foreach $shop->contentExtra() as $service}{$service[0]}-{$service[1]}{if $service@last}{else};{/if}{/foreach}">
-                                <p class="form-control-guide"><i class="mdi mdi-information"></i>例:<code>check-全球节点分布;clear-快速客服响应</code>,减号左边为icon代号右边为文字,以;隔开
-                                </p>
-                                <p class="form-control-guide">icon代号参阅:<a
-                                            href="https://materialdesignicons.com/">Material Design Icons</a>
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-
-                            <div class="form-group">
-                                <div class="row">
-                                    <div class="col-md-10 col-md-push-1">
-                                        <button id="submit" type="submit"
-                                                class="btn btn-block btn-brand waves-attach waves-light">保存
-                                        </button>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                {include file='dialog.tpl'}
-        </div>
-    </div>
-</main>
-
-{include file='admin/footer.tpl'}
-
-<script>
-    window.addEventListener('load', () => {
-        function submit() {
-            if ($$.getElementById('auto_reset_bandwidth').checked) {
-                var auto_reset_bandwidth = 1;
-            } else {
-                var auto_reset_bandwidth = 0;
-            }
-            let contentExtra = $$getValue('content_extra');
-            if (contentExtra === '' || contentExtra === '-') {
-                contentExtra = 'check-全球节点分布;check-快速客服响应;check-全平台客户端';
-            }
-            let data = {
-                name: $$getValue('name'),
-                auto_reset_bandwidth,
-                price: $$getValue('price'),
-                auto_renew: $$getValue('auto_renew'),
-                bandwidth: $$getValue('bandwidth'),
-                speedlimit: $$getValue('speedlimit'),
-                connector: $$getValue('connector'),
-                expire: $$getValue('expire'),
-                class: $$getValue('class'),
-                class_expire: $$getValue('class_expire'),
-                reset: $$getValue('reset'),
-                reset_value: $$getValue('reset_value'),
-                reset_exp: $$getValue('reset_exp'),
-                content_extra: contentExtra,
-            }
-            if ($$.getElementById('traffic-package-enable').checked) {
-                data.traffic_package = {
-                    class: {
-                        min: $$getValue('traffic-package-min'),
-                        max: $$getValue('traffic-package-max')
-                    }
-                }
-            }
-            $.ajax({
-                type: "PUT",
-                url: "/admin/shop/{$shop->id}",
-                dataType: "json",
-                data,
-                success: data => {
-                    if (data.ret) {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                        window.setTimeout("location.href='/admin/shop'", {$config['jump_delay']});
-                    } else {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                    }
-                },
-                error: jqXHR => {
-                    $("#result").modal();
-                    $$.getElementById('msg').innerHTML = `发生错误:${
-                            jqXHR.status
-                            }`;
-                }
-            });
-        }
-        $("html").keydown(event => {
-            if (event.keyCode === 13) {
-                login();
-            }
-        });
-        $$.getElementById('submit').addEventListener('click', submit);
-    })
-</script>

+ 0 - 98
resources/views/tabler/admin/shop/index.tpl

@@ -1,98 +0,0 @@
-{include file='admin/main.tpl'}
-
-<main class="content">
-    <div class="content-header ui-content-header">
-        <div class="container">
-            <h1 class="content-heading">商品列表</h1>
-        </div>
-    </div>
-    <div class="container">
-        <div class="col-lg-12 col-sm-12">
-            <section class="content-inner margin-top-no">
-                <div class="card">
-                    <div class="card-main">
-                        <div class="card-inner">
-                            <p>系统中所有商品的列表。</p>
-                            <p>显示表项:
-                                {include file='table/checkbox.tpl'}
-                            </p>
-                        </div>
-                    </div>
-                </div>
-                <div class="table-responsive">
-                    {include file='table/table.tpl'}
-                </div>
-                <div class="fbtn-container">
-                    <div class="fbtn-inner">
-                        <a class="fbtn fbtn-lg fbtn-brand-accent waves-attach waves-circle waves-light"
-                           href="/admin/shop/create">+</a>
-
-                    </div>
-                </div>
-                <div aria-hidden="true" class="modal modal-va-middle fade" id="delete_modal" role="dialog"
-                     tabindex="-1">
-                    <div class="modal-dialog modal-xs">
-                        <div class="modal-content">
-                            <div class="modal-heading">
-                                <a class="modal-close" data-dismiss="modal">×</a>
-                                <h2 class="modal-title">确认要下架?</h2>
-                            </div>
-                            <div class="modal-inner">
-                                <p>提示:下架会关闭所有购买过的此套餐的自动续费!</p>
-                                <p>请您确认。</p>
-                            </div>
-                            <div class="modal-footer">
-                                <p class="text-right">
-                                    <button class="btn btn-flat btn-brand-accent waves-attach waves-effect"
-                                            data-dismiss="modal" type="button">取消
-                                    </button>
-                                    <button class="btn btn-flat btn-brand-accent waves-attach" data-dismiss="modal"
-                                            id="delete_input" type="button">确定
-                                    </button>
-                                </p>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                {include file='dialog.tpl'}
-        </div>
-    </div>
-</main>
-
-{include file='admin/footer.tpl'}
-
-<script>
-    function delete_modal_show(id) {
-        deleteid = id;
-        $("#delete_modal").modal();
-    }
-    {include file='table/js_1.tpl'}
-    window.addEventListener('load', () => {
-        {include file='table/js_2.tpl'}
-        function delete_id() {
-            $.ajax({
-                type: "DELETE",
-                url: "/admin/shop",
-                dataType: "json",
-                data: {
-                    id: deleteid
-                },
-                success: data => {
-                    if (data.ret) {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                        $$.getElementById(`row_delete_${ldelim}deleteid{rdelim}`).setAttribute('disabled', 'true')
-                    } else {
-                        $("#result").modal();
-                        $$.getElementById('msg').innerHTML = data.msg;
-                    }
-                },
-                error: jqXHR => {
-                    $("#result").modal();
-                    $$.getElementById('msg').innerHTML = `${ldelim}data.msg{rdelim} 发生了错误。`;
-                }
-            });
-        }
-        $$.getElementById('delete_input').addEventListener('click', delete_id);
-    })
-</script>

+ 2 - 2
resources/views/tabler/admin/ticket/index.tpl

@@ -111,7 +111,7 @@
                     }
                 });
             });
-        };
+        }
 
         function deleteTicket(ticket_id) {
             $('#notice-message').text('确定删除此工单?');
@@ -133,7 +133,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 1 - 1
resources/views/tabler/admin/user/index.tpl

@@ -192,7 +192,7 @@
                     }
                 })
             });
-        };
+        }
 
         function reloadTableAjax() {
             table.ajax.reload(null, false);

+ 1 - 1
resources/views/tabler/live_chat.tpl

@@ -44,7 +44,7 @@
 {if $public_setting['live_chat'] == 'livechat'}
 <script>
 window.__lc = window.__lc || { };
-window.__lc.license = "{$public_setting['livechat_id']}";;
+window.__lc.license = "{$public_setting['livechat_id']}";
 window.__lc.params = [
     { name: '用户编号', value: '{$user->id}' },
     { name: '用户类别', value: '{$user->class}' },

+ 0 - 216
resources/views/tabler/telegram_error.tpl

@@ -1,216 +0,0 @@
-<!DOCTYPE HTML>
-<html lang="zh-cn">
-<head>
-    <title>产生了一个错误 - {$config['appName']} </title>
-    <meta name="keywords" content=""/>
-    <meta name="description" content=""/>
-    <meta charset="utf-8"/>
-    <link rel="shortcut icon" href="/favicon.ico"/>
-    <link rel="bookmark" href="/favicon.ico" type="image/x-icon"/>
-    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
-    <link rel="shortcut icon" type="image/ico" href="images/ssr.ico">
-    <style>
-        /*! Spectre.css v0.5.0 | MIT License | github.com/picturepan2/spectre */
-
-        html {
-            font-family: sans-serif;
-            -webkit-text-size-adjust: 100%;
-            -ms-text-size-adjust: 100%
-        }
-
-        body {
-            margin: 0
-        }
-
-        footer {
-            display: block
-        }
-
-        a {
-            background-color: transparent;
-            -webkit-text-decoration-skip: objects
-        }
-
-        a:active,
-        a:hover {
-            outline-width: 0
-        }
-
-        ::-webkit-file-upload-button {
-            -webkit-appearance: button;
-            font: inherit
-        }
-
-        *,
-        ::after,
-        ::before {
-            box-sizing: inherit
-        }
-
-        html {
-            box-sizing: border-box;
-            font-size: 20px;
-            line-height: 1.5;
-            -webkit-tap-highlight-color: transparent
-        }
-
-        body {
-            background: #fff;
-            color: #50596c;
-            font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
-            font-size: .8rem;
-            overflow-x: hidden;
-            text-rendering: optimizeLegibility
-        }
-
-        a {
-            color: #5755d9;
-            outline: 0;
-            text-decoration: none
-        }
-
-        a:focus {
-            box-shadow: 0 0 0 .1rem rgba(87, 85, 217, .2)
-        }
-
-        a:active,
-        a:focus,
-        a:hover {
-            color: #4240d4;
-            text-decoration: underline
-        }
-
-        .h1,
-        .h4 {
-            font-weight: 500
-        }
-
-        .h1 {
-            font-size: 2rem
-        }
-
-        .h4 {
-            font-size: 1.2rem
-        }
-
-        p {
-            margin: 0 0 1rem
-        }
-
-        a {
-            -webkit-text-decoration-skip: ink edges;
-            text-decoration-skip: ink edges
-        }
-
-        .form-input:not(:placeholder-shown):invalid {
-            border-color: #e85600
-        }
-
-        .form-input:not(:placeholder-shown):invalid:focus {
-            box-shadow: 0 0 0 .1rem rgba(232, 86, 0, .2)
-        }
-
-        .container {
-            margin-left: auto;
-            margin-right: auto;
-            padding-left: .4rem;
-            padding-right: .4rem;
-            width: 100%
-        }
-
-        .container.grid-lg {
-            max-width: 976px
-        }
-
-        .empty {
-            background: #f8f9fa;
-            border-radius: .1rem;
-            color: #667189;
-            padding: 3.2rem 1.6rem;
-            text-align: center
-        }
-
-        .empty .empty-subtitle,
-        .empty .empty-title {
-            margin: .4rem auto
-        }
-
-        .empty .empty-action {
-            margin-top: .8rem
-        }
-
-        .text-error {
-            color: #e85600
-        }
-
-        .divider {
-            display: block;
-            position: relative
-        }
-
-        .divider {
-            border-top: .05rem solid #e7e9ed;
-            height: .05rem;
-            margin: .4rem 0
-        }
-
-        .container::after {
-            clear: both;
-            content: "";
-            display: table
-        }
-
-        .centered {
-            display: block;
-            float: none;
-            margin-left: auto;
-            margin-right: auto
-        }
-
-        .valign {
-            display: -webkit-box !important;
-            display: -webkit-flex !important;
-            display: -ms-flexbox !important;
-            display: flex !important;
-            -webkit-box-align: center !important;
-            -webkit-align-items: center !important;
-            -ms-flex-align: center !important;
-            align-items: center !important;
-        }
-
-        .section-footer {
-            color: #acb3c2;
-            padding: 2rem .5rem 0 .5rem;
-            position: relative;
-            z-index: 200;
-        }
-
-        .section-footer a {
-            color: #667189;
-        }
-    </style>
-    {if !empty($redirect)}
-        <meta http-equiv="refresh" content="3; url={$redirect}"/>
-    {/if}
-    <noscript>
-        <link rel="stylesheet" href="/assets/css/noscript.css"/>
-    </noscript>
-</head>
-<body>
-<div class="empty valign" style="height:100vh">
-    <div class="centered">
-        <p class="empty-title h1">{$title}</p>
-        <p class="empty-title h4">{$message}</p>
-        <div class="divider"></div>
-        <div class="empty-action">
-        </div>
-        <footer class="section section-footer">
-            <div id="copyright" class="grid-footer container grid-lg">©
-                <span year="">{date("Y")}</span>
-                <a href="{$config['baseUrl']}" target="_blank">{$config['appName']}</a>
-            </div>
-        </footer>
-    </div>
-</div>
-</body>
-</html>

+ 0 - 216
resources/views/tabler/telegram_success.tpl

@@ -1,216 +0,0 @@
-<!DOCTYPE HTML>
-<html lang="zh-cn">
-<head>
-    <title>正在跳转用户中心 - {$config['appName']} </title>
-    <meta name="keywords" content=""/>
-    <meta name="description" content=""/>
-    <meta charset="utf-8"/>
-    <link rel="shortcut icon" href="/favicon.ico"/>
-    <link rel="bookmark" href="/favicon.ico" type="image/x-icon"/>
-    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
-    <link rel="shortcut icon" type="image/ico" href="images/ssr.ico">
-    <style>
-        /*! Spectre.css v0.5.0 | MIT License | github.com/picturepan2/spectre */
-
-        html {
-            font-family: sans-serif;
-            -webkit-text-size-adjust: 100%;
-            -ms-text-size-adjust: 100%
-        }
-
-        body {
-            margin: 0
-        }
-
-        footer {
-            display: block
-        }
-
-        a {
-            background-color: transparent;
-            -webkit-text-decoration-skip: objects
-        }
-
-        a:active,
-        a:hover {
-            outline-width: 0
-        }
-
-        ::-webkit-file-upload-button {
-            -webkit-appearance: button;
-            font: inherit
-        }
-
-        *,
-        ::after,
-        ::before {
-            box-sizing: inherit
-        }
-
-        html {
-            box-sizing: border-box;
-            font-size: 20px;
-            line-height: 1.5;
-            -webkit-tap-highlight-color: transparent
-        }
-
-        body {
-            background: #fff;
-            color: #50596c;
-            font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
-            font-size: .8rem;
-            overflow-x: hidden;
-            text-rendering: optimizeLegibility
-        }
-
-        a {
-            color: #5755d9;
-            outline: 0;
-            text-decoration: none
-        }
-
-        a:focus {
-            box-shadow: 0 0 0 .1rem rgba(87, 85, 217, .2)
-        }
-
-        a:active,
-        a:focus,
-        a:hover {
-            color: #4240d4;
-            text-decoration: underline
-        }
-
-        .h1,
-        .h4 {
-            font-weight: 500
-        }
-
-        .h1 {
-            font-size: 2rem
-        }
-
-        .h4 {
-            font-size: 1.2rem
-        }
-
-        p {
-            margin: 0 0 1rem
-        }
-
-        a {
-            -webkit-text-decoration-skip: ink edges;
-            text-decoration-skip: ink edges
-        }
-
-        .form-input:not(:placeholder-shown):invalid {
-            border-color: #e85600
-        }
-
-        .form-input:not(:placeholder-shown):invalid:focus {
-            box-shadow: 0 0 0 .1rem rgba(232, 86, 0, .2)
-        }
-
-        .container {
-            margin-left: auto;
-            margin-right: auto;
-            padding-left: .4rem;
-            padding-right: .4rem;
-            width: 100%
-        }
-
-        .container.grid-lg {
-            max-width: 976px
-        }
-
-        .empty {
-            background: #f8f9fa;
-            border-radius: .1rem;
-            color: #667189;
-            padding: 3.2rem 1.6rem;
-            text-align: center
-        }
-
-        .empty .empty-subtitle,
-        .empty .empty-title {
-            margin: .4rem auto
-        }
-
-        .empty .empty-action {
-            margin-top: .8rem
-        }
-
-        .text-error {
-            color: #e85600
-        }
-
-        .divider {
-            display: block;
-            position: relative
-        }
-
-        .divider {
-            border-top: .05rem solid #e7e9ed;
-            height: .05rem;
-            margin: .4rem 0
-        }
-
-        .container::after {
-            clear: both;
-            content: "";
-            display: table
-        }
-
-        .centered {
-            display: block;
-            float: none;
-            margin-left: auto;
-            margin-right: auto
-        }
-
-        .valign {
-            display: -webkit-box !important;
-            display: -webkit-flex !important;
-            display: -ms-flexbox !important;
-            display: flex !important;
-            -webkit-box-align: center !important;
-            -webkit-align-items: center !important;
-            -ms-flex-align: center !important;
-            align-items: center !important;
-        }
-
-        .section-footer {
-            color: #acb3c2;
-            padding: 2rem .5rem 0 .5rem;
-            position: relative;
-            z-index: 200;
-        }
-
-        .section-footer a {
-            color: #667189;
-        }
-    </style>
-    {if !empty($redirect)}
-        <meta http-equiv="refresh" content="3; url={$redirect}"/>
-    {/if}
-    <noscript>
-        <link rel="stylesheet" href="/assets/css/noscript.css"/>
-    </noscript>
-</head>
-<body>
-<div class="empty valign" style="height:100vh">
-    <div class="centered">
-        <p class="empty-title h1">{$title}</p>
-        <p class="empty-title h4">{$message}</p>
-        <div class="divider"></div>
-        <div class="empty-action">
-        </div>
-        <footer class="section section-footer">
-            <div id="copyright" class="grid-footer container grid-lg">©
-                <span year="">{date("Y")}</span>
-                <a href="{$config['baseUrl']}" target="_blank">{$config['appName']}</a>
-            </div>
-        </footer>
-    </div>
-</div>
-</body>
-</html>

+ 23 - 25
src/Command/ClientDownload.php

@@ -5,6 +5,10 @@ declare(strict_types=1);
 namespace App\Command;
 
 use Exception;
+use GuzzleHttp\Client;
+use function json_decode;
+use function json_encode;
+use function time;
 
 /**
  * 世界这么大,何必要让它更艰难呢?
@@ -13,14 +17,14 @@ use Exception;
  */
 final class ClientDownload extends Command
 {
-    public $description = '├─=: php xcat ClientDownload - 定时更新客户端' . PHP_EOL;
+    public string $description = '├─=: php xcat ClientDownload - 定时更新客户端' . PHP_EOL;
 
     private $client;
 
     /**
      * 保存基本路径
      */
-    private $basePath = BASE_PATH . '/';
+    private string $basePath = BASE_PATH . '/';
 
     /**
      * 下载配置
@@ -29,14 +33,14 @@ final class ClientDownload extends Command
 
     public function boot(): void
     {
-        $this->client = new \GuzzleHttp\Client();
+        $this->client = new Client();
         $this->version = $this->getLocalVersions();
         $clientsPath = BASE_PATH . '/config/clients.json';
         if (! is_file($clientsPath)) {
             echo 'clients.json 不存在,脚本中止.' . PHP_EOL;
             exit(0);
         }
-        $clients = \json_decode(file_get_contents($clientsPath), true);
+        $clients = json_decode(file_get_contents($clientsPath), true);
         foreach ($clients['clients'] as $client) {
             $this->getSoft($client);
         }
@@ -77,7 +81,7 @@ final class ClientDownload extends Command
     {
         $url = 'https://api.github.com/repos/' . $repo . '/releases/latest' . ($_ENV['github_access_token'] !== '' ? '?access_token=' . $_ENV['github_access_token'] : '');
         $request = $this->client->get($url);
-        return (string) \json_decode(
+        return (string) json_decode(
             $request->getBody()->getContents(),
             true
         )['tag_name'];
@@ -90,7 +94,7 @@ final class ClientDownload extends Command
     {
         $url = 'https://api.github.com/repos/' . $repo . '/releases' . ($_ENV['github_access_token'] !== '' ? '?access_token=' . $_ENV['github_access_token'] : '');
         $request = $this->client->get($url);
-        $latest = \json_decode(
+        $latest = json_decode(
             $request->getBody()->getContents(),
             true
         )[0];
@@ -105,7 +109,7 @@ final class ClientDownload extends Command
         $request = $this->client->get($url);
         preg_match('#(?<=\<span\sitemprop="version">)[^<]+#', $request->getBody()->getContents(), $tagName);
         preg_match('#[\d\.]+#', $tagName[0], $tagNum);
-        return (string) $tagNum[0];
+        return $tagNum[0];
     }
 
     /**
@@ -113,7 +117,7 @@ final class ClientDownload extends Command
      */
     private function isJson(string $string): bool
     {
-        return \json_decode($string, true) !== false;
+        return json_decode($string, true) !== false;
     }
 
     /**
@@ -129,9 +133,9 @@ final class ClientDownload extends Command
             echo '本地软体版本库 LocalClientVersion.json 不存在,创建文件中...' . PHP_EOL;
             $result = file_put_contents(
                 $filePath,
-                \json_encode(
+                json_encode(
                     [
-                        'createTime' => \time(),
+                        'createTime' => time(),
                     ]
                 )
             );
@@ -145,19 +149,19 @@ final class ClientDownload extends Command
             echo 'LocalClientVersion.json 文件格式异常,脚本中止.' . PHP_EOL;
             exit(0);
         }
-        return \json_decode($fileContent, true);
+        return json_decode($fileContent, true);
     }
 
     /**
      * 储存本地软体版本库
      */
-    private function setLocalVersions(array $versions): bool
+    private function setLocalVersions(array $versions): void
     {
         $fileName = 'LocalClientVersion.json';
         $filePath = BASE_PATH . '/storage/' . $fileName;
-        return (bool) file_put_contents(
+        (bool) file_put_contents(
             $filePath,
-            \json_encode(
+            json_encode(
                 $versions
             )
         );
@@ -167,17 +171,11 @@ final class ClientDownload extends Command
     {
         $savePath = $this->basePath . $task['savePath'];
         echo '====== ' . $task['name'] . ' 开始 ======' . PHP_EOL;
-        switch ($task['tagMethod']) {
-            case 'github_pre_release':
-                $tagMethod = 'getLatestPreReleaseTagName';
-                break;
-            case 'apkpure':
-                $tagMethod = 'getApkpureTagName';
-                break;
-            default:
-                $tagMethod = 'getLatestReleaseTagName';
-                break;
-        }
+        $tagMethod = match ($task['tagMethod']) {
+            'github_pre_release' => 'getLatestPreReleaseTagName',
+            'apkpure' => 'getApkpureTagName',
+            default => 'getLatestReleaseTagName',
+        };
         $tagName = $this->$tagMethod($task['gitRepo']);
         if (! isset($this->version[$task['name']])) {
             echo '- 本地不存在 ' . $task['name'] . ',检测到当前最新版本为 ' . $tagName . PHP_EOL;

+ 22 - 15
src/Command/Cron.php

@@ -9,10 +9,14 @@ use App\Models\Order;
 use App\Models\User;
 use App\Utils\Tools;
 use DateTime;
+use Exception;
+use function in_array;
+use function json_decode;
+use function time;
 
 final class Cron extends Command
 {
-    public $description = <<<EOL
+    public string $description = <<<EOL
 ├─=: php xcat Cron - 站点定时任务,每五分钟
 EOL;
 
@@ -31,24 +35,23 @@ EOL;
                 continue;
             }
             // 标记订单为等待激活
-            if (\in_array($invoice->status, ['paid_gateway', 'paid_balance', 'paid_admin'])) {
+            if (in_array($invoice->status, ['paid_gateway', 'paid_balance', 'paid_admin'])) {
                 $order->status = 'pending_activation';
-                $order->update_time = \time();
+                $order->update_time = time();
                 $order->save();
                 echo "已标记订单 #{$order->id} 为等待激活。\n";
                 continue;
             }
             // 取消超时未支付的订单和关联账单
-            if ($order->create_time + 86400 < \time()) {
+            if ($order->create_time + 86400 < time()) {
                 $order->status = 'cancelled';
-                $order->update_time = \time();
+                $order->update_time = time();
                 $order->save();
                 echo "已取消超时订单 #{$order->id}。\n";
                 $invoice->status = 'cancelled';
-                $invoice->update_time = \time();
+                $invoice->update_time = time();
                 $invoice->save();
                 echo "已取消超时账单 #{$invoice->id}。\n";
-                continue;
             }
         }
 
@@ -66,12 +69,17 @@ EOL;
                 if ($pending_activation_orders !== null) {
                     $order = $pending_activation_orders[0];
                     $order->status = 'activated';
-                    $order->update_time = \time();
+                    $order->update_time = time();
                     $order->save();
                     // 获取订单内容准备激活
-                    $content = \json_decode($order->product_content);
+                    $content = json_decode($order->product_content);
                     // 激活商品
-                    $old_expire_in = new DateTime($user->expire_in);
+                    $old_expire_in = null;
+                    try {
+                        $old_expire_in = new DateTime($user->expire_in);
+                    } catch (Exception $e) {
+                        continue;
+                    }
                     $user->expire_in = $old_expire_in->modify('+' . $content->time . ' days')->format('Y-m-d H:i:s');
                     $user->u = 0;
                     $user->d = 0;
@@ -90,13 +98,12 @@ EOL;
             }
             // 如果用户账户中有已激活的订单,则判断是否过期
             if ($activated_order !== null) {
-                $content = \json_decode($activated_order->product_content);
-                if ($activated_order->update_time + $content->time * 86400 < \time()) {
+                $content = json_decode($activated_order->product_content);
+                if ($activated_order->update_time + $content->time * 86400 < time()) {
                     $activated_order->status = 'expired';
-                    $activated_order->update_time = \time();
+                    $activated_order->update_time = time();
                     $activated_order->save();
-                    echo "订单 #{$order->id} 已过期。\n";
-                    continue;
+                    echo "订单 #{$activated_order->id} 已过期。\n";
                 }
             }
         }

+ 15 - 5
src/Command/DetectBan.php

@@ -7,10 +7,11 @@ namespace App\Command;
 use App\Models\DetectBanLog;
 use App\Models\DetectLog;
 use App\Models\User;
+use function in_array;
 
 final class DetectBan extends Command
 {
-    public $description = '├─=: php xcat DetectBan      - 审计封禁定时任务' . PHP_EOL;
+    public string $description = '├─=: php xcat DetectBan      - 审计封禁定时任务' . PHP_EOL;
 
     /**
      * 审计封禁任务
@@ -20,13 +21,17 @@ final class DetectBan extends Command
         if ($_ENV['enable_auto_detect_ban'] === false) {
             return;
         }
+
         echo '审计封禁检查开始.' . PHP_EOL;
+
         $new_logs = DetectLog::where('status', '=', 0)->orderBy('id', 'asc')->take($_ENV['auto_detect_ban_numProcess'])->get();
+
         if (count($new_logs) !== 0) {
             $user_logs = [];
+
             foreach ($new_logs as $log) {
                 // 分类各个用户的记录数量
-                if (! \in_array($log->user_id, array_keys($user_logs))) {
+                if (! in_array($log->user_id, array_keys($user_logs))) {
                     $user_logs[$log->user_id] = 0;
                 }
                 $user_logs[$log->user_id]++;
@@ -37,13 +42,15 @@ final class DetectBan extends Command
             foreach ($user_logs as $userid => $value) {
                 // 执行封禁
                 $user = User::find($userid);
+
                 if ($user === null) {
                     continue;
                 }
+
                 $user->all_detect_number += $value;
                 $user->save();
 
-                if ($user->is_banned === 1 || ($user->is_admin && $_ENV['auto_detect_ban_allow_admin'] === true) || \in_array($user->id, $_ENV['auto_detect_ban_allow_users'])) {
+                if ($user->is_banned === 1 || ($user->is_admin && $_ENV['auto_detect_ban_allow_admin'] === true) || in_array($user->id, $_ENV['auto_detect_ban_allow_users'])) {
                     // 如果用户已被封禁
                     // 如果用户是管理员
                     // 如果属于钦定用户
@@ -53,8 +60,9 @@ final class DetectBan extends Command
 
                 if ($_ENV['auto_detect_ban_type'] === 1) {
                     $last_DetectBanLog = DetectBanLog::where('user_id', $userid)->orderBy('id', 'desc')->first();
-                    $last_all_detect_number = ($last_DetectBanLog === null ? 0 : (int) $last_DetectBanLog->all_detect_number);
+                    $last_all_detect_number = ((int) $last_DetectBanLog?->all_detect_number);
                     $detect_number = $user->all_detect_number - $last_all_detect_number;
+
                     if ($detect_number >= $_ENV['auto_detect_ban_number']) {
                         $last_detect_ban_time = $user->last_detect_ban_time;
                         $end_time = date('Y-m-d H:i:s');
@@ -75,13 +83,15 @@ final class DetectBan extends Command
                 } else {
                     $number = $user->all_detect_number;
                     $tmp = 0;
-                    foreach ($_ENV['auto_detect_ban'] as $key => $value) {
+
+                    foreach ($_ENV['auto_detect_ban'] as $key => $val) {
                         if ($number >= $key) {
                             if ($key >= $tmp) {
                                 $tmp = $key;
                             }
                         }
                     }
+
                     if ($tmp !== 0) {
                         if ($_ENV['auto_detect_ban'][$tmp]['type'] === 'kill') {
                             $user->killUser();

+ 18 - 6
src/Command/DetectGFW.php

@@ -8,19 +8,25 @@ use App\Models\Node;
 use App\Models\Setting;
 use App\Models\User;
 use App\Utils\Telegram;
+use Telegram\Bot\Exceptions\TelegramSDKException;
+use function json_decode;
+use function time;
 
 final class DetectGFW extends Command
 {
-    public $description = '├─=: php xcat DetectGFW      - 节点被墙检测定时任务' . PHP_EOL;
+    public string $description = '├─=: php xcat DetectGFW      - 节点被墙检测定时任务' . PHP_EOL;
 
+    /**
+     * @throws TelegramSDKException
+     */
     public function boot(): void
     {
         //节点被墙检测
         $last_time = file_get_contents(BASE_PATH . '/storage/last_detect_gfw_time');
         for ($count = 1; $count <= 12; $count++) {
-            if (\time() - $last_time >= $_ENV['detect_gfw_interval']) {
+            if (time() - $last_time >= $_ENV['detect_gfw_interval']) {
                 $file_interval = fopen(BASE_PATH . '/storage/last_detect_gfw_time', 'wb');
-                fwrite($file_interval, (string) \time());
+                fwrite($file_interval, (string) time());
                 fclose($file_interval);
                 $nodes = Node::all();
                 $adminUser = User::where('is_admin', '=', '1')->get();
@@ -41,13 +47,17 @@ final class DetectGFW extends Command
                     //因为考虑到有v2ray之类的节点,所以不得不使用ip作为参数
                     $result_tcping = false;
                     $detect_time = $_ENV['detect_gfw_count'];
+
                     for ($i = 1; $i <= $detect_time; $i++) {
-                        $json_tcping = \json_decode(file_get_contents($api_url), true);
+                        $json_tcping = json_decode(file_get_contents($api_url), true);
                         if ($json_tcping['status'] === 'true') {
                             $result_tcping = true;
                             break;
                         }
                     }
+
+                    $notice_text = '';
+
                     if ($result_tcping === false) {
                         //被墙了
                         echo $node->id . ':false' . PHP_EOL;
@@ -55,6 +65,7 @@ final class DetectGFW extends Command
                         if ($node->gfw_block === true) {
                             continue;
                         }
+
                         foreach ($adminUser as $user) {
                             echo 'Send gfw mail to user: ' . $user->id . '-';
                             $user->sendMail(
@@ -71,11 +82,11 @@ final class DetectGFW extends Command
                                 Setting::obtain('telegram_node_gfwed_text')
                             );
                         }
+
                         if (Setting::obtain('telegram_node_gfwed')) {
                             Telegram::send($notice_text);
                         }
                         $node->gfw_block = true;
-                        $node->save();
                     } else {
                         //没有被墙
                         echo $node->id . ':true' . PHP_EOL;
@@ -102,8 +113,9 @@ final class DetectGFW extends Command
                             Telegram::send($notice_text);
                         }
                         $node->gfw_block = false;
-                        $node->save();
                     }
+
+                    $node->save();
                 }
                 break;
             }

+ 1 - 1
src/Command/FinanceMail.php

@@ -11,7 +11,7 @@ use Ozdemir\Datatables\DB\MySQL;
 
 final class FinanceMail extends Command
 {
-    public $description = <<<EOL
+    public string $description = <<<EOL
 ├─=: php xcat FinanceMail [选项]
 │ ├─ day                     - 日报
 │ ├─ week                    - 周报

+ 36 - 25
src/Command/Job.php

@@ -26,10 +26,15 @@ use App\Services\Mail;
 use App\Utils\Telegram;
 use App\Utils\Tools;
 use Exception;
+use Psr\Http\Client\ClientExceptionInterface;
+use Telegram\Bot\Exceptions\TelegramSDKException;
+use function in_array;
+use function json_decode;
+use function time;
 
 final class Job extends Command
 {
-    public $description = <<<EOL
+    public string $description = <<<EOL
 ├─=: php xcat Job [选项]
 │ ├─ DailyJob                - 每日任务,每天
 │ ├─ CheckJob                - 检查任务,每分钟
@@ -62,15 +67,15 @@ EOL;
         // ------- 重置节点流量
 
         // ------- 清理各表记录
-        UserSubscribeLog::where('request_time', '<', date('Y-m-d H:i:s', \time() - 86400 * (int) $_ENV['subscribeLog_keep_days']))->delete();
-        UserHourlyUsage::where('datetime', '<', \time() - 86400 * (int) $_ENV['trafficLog_keep_days'])->delete();
-        DetectLog::where('datetime', '<', \time() - 86400 * 3)->delete();
-        EmailVerify::where('expire_in', '<', \time() - 86400 * 3)->delete();
-        EmailQueue::where('time', '<', \time() - 86400 * 3)->delete();
-        PasswordReset::where('expire_time', '<', \time() - 86400 * 3)->delete();
-        Ip::where('datetime', '<', \time() - 300)->delete();
-        StreamMedia::where('created_at', '<', \time() - 86400 * 3)->delete();
-        TelegramSession::where('datetime', '<', \time() - 900)->delete();
+        UserSubscribeLog::where('request_time', '<', date('Y-m-d H:i:s', time() - 86400 * (int) $_ENV['subscribeLog_keep_days']))->delete();
+        UserHourlyUsage::where('datetime', '<', time() - 86400 * (int) $_ENV['trafficLog_keep_days'])->delete();
+        DetectLog::where('datetime', '<', time() - 86400 * 3)->delete();
+        EmailVerify::where('expire_in', '<', time() - 86400 * 3)->delete();
+        EmailQueue::where('time', '<', time() - 86400 * 3)->delete();
+        PasswordReset::where('expire_time', '<', time() - 86400 * 3)->delete();
+        Ip::where('datetime', '<', time() - 300)->delete();
+        StreamMedia::where('created_at', '<', time() - 86400 * 3)->delete();
+        TelegramSession::where('datetime', '<', time() - 900)->delete();
         // ------- 清理各表记录
 
         // ------- 用户每日流量报告
@@ -147,7 +152,7 @@ EOL;
 
         // ------- 免费用户流量重置
         foreach ($users as $user) {
-            if (\in_array($user->id, $bought_users)) {
+            if (in_array($user->id, $bought_users)) {
                 continue;
             }
             // 跳过使用新商店系统的用户
@@ -210,14 +215,17 @@ EOL;
 
     /**
      * 检查任务,每分钟
+     *
+     * @throws TelegramSDKException
+     * @throws ClientExceptionInterface
      */
     public function CheckJob(): void
     {
         //记录当前时间戳
-        $timestatmp = \time();
+        $timestatmp = time();
         //邮件队列处理
         while (true) {
-            if (\time() - $timestatmp > 59) {
+            if (time() - $timestatmp > 59) {
                 echo '邮件队列处理超时,已跳过' . PHP_EOL;
                 break;
             }
@@ -235,7 +243,7 @@ EOL;
             DB::delete('DELETE FROM email_queue WHERE id = ?', [$email_queue['id']]);
             if (Tools::isEmail($email_queue['to_email'])) {
                 try {
-                    Mail::send($email_queue['to_email'], $email_queue['subject'], $email_queue['template'], \json_decode($email_queue['array']), []);
+                    Mail::send($email_queue['to_email'], $email_queue['subject'], $email_queue['template'], json_decode($email_queue['array']));
                 } catch (Exception $e) {
                     echo $e->getMessage();
                 }
@@ -250,6 +258,7 @@ EOL;
             $adminUser = User::where('is_admin', '=', '1')->get();
             $nodes = Node::all();
             foreach ($nodes as $node) {
+                $notice_text = '';
                 if ($node->isNodeOnline() === false && $node->online === true) {
                     if ($_ENV['useScFtqq'] === true) {
                         $ScFtqq_SCKEY = $_ENV['ScFtqq_SCKEY'];
@@ -316,6 +325,7 @@ EOL;
                         $context = stream_context_create($opts);
                         file_get_contents('https://sctapi.ftqq.com/' . $ScFtqq_SCKEY . '.send', false, $context);
                     }
+
                     foreach ($adminUser as $user) {
                         echo 'Send offline mail to user: ' . $user->id . PHP_EOL;
                         $user->sendMail(
@@ -376,11 +386,11 @@ EOL;
                 $trafficlog->user_id = $user->id;
                 $trafficlog->traffic = $transfer_total;
                 $trafficlog->hourly_usage = $transfer_total - $transfer_total_last;
-                $trafficlog->datetime = \time();
+                $trafficlog->datetime = time();
                 $trafficlog->save();
             }
 
-            if (strtotime($user->expire_in) < \time() && $user->expire_notified === false) {
+            if (strtotime($user->expire_in) < time() && $user->expire_notified === false) {
                 $user->transfer_enable = 0;
                 $user->u = 0;
                 $user->d = 0;
@@ -396,7 +406,7 @@ EOL;
                 );
                 $user->expire_notified = true;
                 $user->save();
-            } elseif (strtotime($user->expire_in) > \time() && $user->expire_notified === true) {
+            } elseif (strtotime($user->expire_in) > time() && $user->expire_notified === true) {
                 $user->expire_notified = false;
                 $user->save();
             }
@@ -405,6 +415,7 @@ EOL;
             if ($_ENV['notify_limit_mode'] !== false) {
                 $user_traffic_left = $user->transfer_enable - $user->u - $user->d;
                 $under_limit = false;
+                $unit_text = '';
 
                 if ($user->transfer_enable !== 0 && $user->class !== 0) {
                     if (
@@ -444,7 +455,7 @@ EOL;
 
             if (
                 $_ENV['account_expire_delete_days'] >= 0 &&
-                strtotime($user->expire_in) + $_ENV['account_expire_delete_days'] * 86400 < \time() &&
+                strtotime($user->expire_in) + $_ENV['account_expire_delete_days'] * 86400 < time() &&
                 $user->money <= $_ENV['auto_clean_min_money']
             ) {
                 $user->sendMail(
@@ -465,7 +476,7 @@ EOL;
                 max(
                     $user->last_check_in_time,
                     strtotime($user->reg_date)
-                ) + ($_ENV['auto_clean_uncheck_days'] * 86400) < \time() &&
+                ) + ($_ENV['auto_clean_uncheck_days'] * 86400) < time() &&
                 $user->class === 0 &&
                 $user->money <= $_ENV['auto_clean_min_money']
             ) {
@@ -484,7 +495,7 @@ EOL;
 
             if (
                 $_ENV['auto_clean_unused_days'] > 0 &&
-                max($user->t, strtotime($user->reg_date)) + ($_ENV['auto_clean_unused_days'] * 86400) < \time() &&
+                max($user->t, strtotime($user->reg_date)) + ($_ENV['auto_clean_unused_days'] * 86400) < time() &&
                 $user->class === 0 &&
                 $user->money <= $_ENV['auto_clean_min_money']
             ) {
@@ -503,7 +514,7 @@ EOL;
 
             if (
                 $user->class !== 0 &&
-                strtotime($user->class_expire) < \time() &&
+                strtotime($user->class_expire) < time() &&
                 strtotime($user->class_expire) > 1420041600
             ) {
                 $text = '您好,系统发现您的账号等级已经过期了。';
@@ -531,7 +542,7 @@ EOL;
             if ($user->is_banned === 1) {
                 $logs = DetectBanLog::where('user_id', $user->id)->orderBy('id', 'desc')->first();
                 if ($logs !== null) {
-                    if (($logs->end_time + $logs->ban_time * 60) <= \time()) {
+                    if (($logs->end_time + $logs->ban_time * 60) <= time()) {
                         $user->is_banned = 0;
                     }
                 }
@@ -541,7 +552,7 @@ EOL;
         }
 
         //自动续费
-        $boughts = Bought::where('renew', '<', \time() + 60)->where('renew', '<>', 0)->get();
+        $boughts = Bought::where('renew', '<', time() + 60)->where('renew', '<>', 0)->get();
         foreach ($boughts as $bought) {
             /** @var Bought $bought */
             $user = $bought->user();
@@ -582,8 +593,8 @@ EOL;
                 $bought_new = new Bought();
                 $bought_new->userid = $user->id;
                 $bought_new->shopid = $shop->id;
-                $bought_new->datetime = \time();
-                $bought_new->renew = \time() + $shop->auto_renew * 86400;
+                $bought_new->datetime = time();
+                $bought_new->renew = time() + $shop->auto_renew * 86400;
                 $bought_new->price = $shop->price;
                 $bought_new->coupon = '';
                 $bought_new->save();

+ 3 - 5
src/Command/Migration.php

@@ -13,13 +13,12 @@ use function is_numeric;
 use function krsort;
 use function ksort;
 use function scandir;
-use function substr;
 use const PHP_INT_MAX;
 use const SCANDIR_SORT_NONE;
 
 final class Migration extends Command
 {
-    public $description = <<< END
+    public string $description = <<< END
 ├─=: php xcat Migration [版本]
 │ ├─ <version>               - 迁移至指定版本(前进/退回)
 │ ├─ latest                  - 迁移至最新版本
@@ -47,7 +46,6 @@ END;
         } elseif ($target === 'new') {
             $tables = DB::select('SHOW TABLES');
             if ($tables === []) {
-                $min_version = 0;
                 $max_version = PHP_INT_MAX;
             } else {
                 echo "Database is not empty, do not use \"new\" as version.\n";
@@ -74,11 +72,11 @@ END;
         $files = scandir(BASE_PATH . '/db/migrations/', SCANDIR_SORT_NONE);
         if ($files) {
             foreach ($files as $file) {
-                if ($file === '.' || $file === '..' || substr($file, -4) !== '.php') {
+                if ($file === '.' || $file === '..' || ! str_ends_with($file, '.php')) {
                     continue;
                 }
                 $version = (int) explode('-', $file, 1)[0];
-                echo "Found migration version {$version}";
+                echo "Found migration version {$version}.";
                 if ($version <= $min_version || $version > $max_version) {
                     echo "...skip\n";
                     continue;

+ 45 - 21
src/Command/Tool.php

@@ -11,11 +11,17 @@ use App\Utils\Hash;
 use App\Utils\Tools;
 use Exception;
 use Ramsey\Uuid\Uuid;
+use Telegram\Bot\Api;
+use Telegram\Bot\Exceptions\TelegramSDKException;
 use Vectorface\GoogleAuthenticator;
+use function in_array;
+use function json_decode;
+use function json_encode;
+use function time;
 
 final class Tool extends Command
 {
-    public $description = <<<EOL
+    public string $description = <<<EOL
 ├─=: php xcat Tool [选项]
 │ ├─ setTelegram             - 设置 Telegram 机器人
 │ ├─ resetAllSettings        - 使用默认值覆盖设置中心设置
@@ -48,11 +54,17 @@ EOL;
         }
     }
 
+    /**
+     * @throws TelegramSDKException
+     */
     public function setTelegram(): void
     {
         $WebhookUrl = $_ENV['baseUrl'] . '/telegram_callback?token=' . $_ENV['telegram_request_token'];
-        $telegram = new \Telegram\Bot\Api($_ENV['telegram_token']);
+
+        $telegram = new Api($_ENV['telegram_token']);
+
         $telegram->removeWebhook();
+
         if ($telegram->setWebhook(['url' => $WebhookUrl])) {
             echo 'Bot @' . $telegram->getMe()->getUsername() . ' 设置成功!' . PHP_EOL;
         } else {
@@ -83,7 +95,7 @@ EOL;
             $setting->value = $setting->default;
         }
 
-        $json_settings = \json_encode($settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
+        $json_settings = json_encode($settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
         file_put_contents('./config/settings.json', $json_settings);
 
         echo '已导出所有数据库设置' . PHP_EOL;
@@ -92,7 +104,7 @@ EOL;
     public function importAllSettings(): void
     {
         $json_settings = file_get_contents('./config/settings.json');
-        $settings = \json_decode($json_settings, true);
+        $settings = json_decode($json_settings, true);
         $config = [];
         $add_counter = 0;
         $del_counter = 0;
@@ -115,26 +127,26 @@ EOL;
                 $new_item->mark = $item['mark'];
                 $new_item->save();
 
-                echo "添加新数据库设置:${item_name}" . PHP_EOL;
+                echo "添加新数据库设置:{$item_name}" . PHP_EOL;
                 $add_counter += 1;
             }
         }
         // 检查移除
         $db_settings = Setting::all();
         foreach ($db_settings as $db_setting) {
-            if (! \in_array($db_setting->item, $config)) {
+            if (! in_array($db_setting->item, $config)) {
                 $db_setting->delete();
                 $del_counter += 1;
             }
         }
 
         if ($add_counter !== 0) {
-            echo "总计添加了 ${add_counter} 项新数据库设置" . PHP_EOL;
+            echo "总计添加了 {$add_counter} 项新数据库设置" . PHP_EOL;
         } else {
             echo '没有任何新数据库设置项需要添加' . PHP_EOL;
         }
         if ($del_counter !== 0) {
-            echo "总计移除了 ${del_counter} 项数据库设置" . PHP_EOL;
+            echo "总计移除了 {$del_counter} 项数据库设置" . PHP_EOL;
         }
     }
 
@@ -203,7 +215,7 @@ EOL;
     public function generateUUID(): void
     {
         $users = ModelsUser::all();
-        $current_timestamp = \time();
+        $current_timestamp = time();
         foreach ($users as $user) {
             /** @var ModelsUser $user */
             $user->generateUUID($current_timestamp);
@@ -218,8 +230,15 @@ EOL;
     {
         $users = ModelsUser::all();
         foreach ($users as $user) {
+            $secret = '';
             $ga = new GoogleAuthenticator();
-            $secret = $ga->createSecret();
+
+            try {
+                $secret = $ga->createSecret();
+            } catch (Exception $e) {
+                echo $e->getMessage();
+            }
+
             $user->ga_token = $secret;
             $user->save();
         }
@@ -232,7 +251,7 @@ EOL;
     public function generateApiToken(): void
     {
         $users = ModelsUser::all();
-        $current_timestamp = \time();
+        $current_timestamp = time();
         foreach ($users as $user) {
             /** @var ModelsUser $user */
             $user->generateApiToken($current_timestamp);
@@ -245,21 +264,19 @@ EOL;
      */
     public function createAdmin(): void
     {
+        $y = '';
+        $email = '';
+        $passwd = '';
+
         if (count($this->argv) === 3) {
             // ask for input
             fwrite(STDOUT, '(1/3) 请输入管理员邮箱:') . PHP_EOL;
             // get input
             $email = trim(fgets(STDIN));
-            if ($email === null) {
-                die("必须输入管理员邮箱.\r\n");
-            }
 
             // write input back
             fwrite(STDOUT, '(2/3) 请输入管理员账户密码:') . PHP_EOL;
             $passwd = trim(fgets(STDIN));
-            if ($passwd === null) {
-                die("必须输入管理员密码.\r\n");
-            }
 
             fwrite(STDOUT, '(3/3) 按 Y 或 y 确认创建:');
             $y = trim(fgets(STDIN));
@@ -269,7 +286,7 @@ EOL;
         }
 
         if (strtolower($y) === 'y') {
-            $current_timestamp = \time();
+            $current_timestamp = time();
             // create admin user
             $configs = Setting::getClass('register');
             // do reg user
@@ -289,7 +306,7 @@ EOL;
             $user->invite_num = $configs['sign_up_for_invitation_codes'];
             $user->ref_by = 0;
             $user->is_admin = 1;
-            $user->expire_in = date('Y-m-d H:i:s', \time() + $configs['sign_up_for_free_time'] * 86400);
+            $user->expire_in = date('Y-m-d H:i:s', time() + $configs['sign_up_for_free_time'] * 86400);
             $user->reg_date = date('Y-m-d H:i:s');
             $user->money = 0;
             $user->im_type = 1;
@@ -299,7 +316,14 @@ EOL;
             $user->theme = $_ENV['theme'];
 
             $ga = new GoogleAuthenticator();
-            $secret = $ga->createSecret();
+            $secret = '';
+
+            try {
+                $secret = $ga->createSecret();
+            } catch (Exception $e) {
+                echo $e->getMessage();
+            }
+
             $user->ga_token = $secret;
             $user->ga_enable = 0;
 
@@ -320,7 +344,7 @@ EOL;
     {
         if (count($this->argv) === 4) {
             $user = ModelsUser::find($this->argv[3]);
-            $expire_in = 86400 + \time();
+            $expire_in = 86400 + time();
             echo Hash::cookieHash($user->pass, $expire_in) . ' ' . $expire_in;
         }
     }

+ 1 - 1
src/Command/Update.php

@@ -6,7 +6,7 @@ namespace App\Command;
 
 final class Update extends Command
 {
-    public $description = <<< END
+    public string $description = <<< END
 ├─=: php xcat Update         - 更新并迁移配置
 END;
 

+ 16 - 18
src/Controllers/Admin/AnnController.php

@@ -9,12 +9,14 @@ use App\Models\Ann;
 use App\Models\User;
 use App\Utils\Telegram;
 use League\HTMLToMarkdown\HtmlConverter;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use Telegram\Bot\Exceptions\TelegramSDKException;
 
 final class AnnController extends BaseController
 {
-    public static $details =
+    public static array $details =
     [
         'field' => [
             'op' => '操作',
@@ -24,16 +26,16 @@ final class AnnController extends BaseController
         ],
     ];
 
-    public static $update_field = [
+    public static array $update_field = [
         'email_notify_class',
     ];
 
     /**
      * 后台公告页面
      *
-     * @param array     $args
+     * @noinspection PhpUnhandledExceptionInspection
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -45,9 +47,9 @@ final class AnnController extends BaseController
     /**
      * 后台公告创建页面
      *
-     * @param array     $args
+     * @noinspection PhpUnhandledExceptionInspection
      */
-    public function create(ServerRequest $request, Response $response, array $args)
+    public function create(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -59,9 +61,9 @@ final class AnnController extends BaseController
     /**
      * 后台添加公告
      *
-     * @param array     $args
+     * @throws TelegramSDKException
      */
-    public function add(ServerRequest $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $email_notify_class = (int) $request->getParam('email_notify_class');
         $email_notify = (int) $request->getParam('email_notify');
@@ -113,9 +115,9 @@ final class AnnController extends BaseController
     /**
      * 后台编辑公告页面
      *
-     * @param array     $args
+     * @noinspection PhpUnhandledExceptionInspection
      */
-    public function edit(ServerRequest $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $ann = Ann::find($args['id']);
         return $response->write(
@@ -128,9 +130,9 @@ final class AnnController extends BaseController
     /**
      * 后台编辑公告提交
      *
-     * @param array     $args
+     * @throws TelegramSDKException
      */
-    public function update(ServerRequest $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $ann = Ann::find($args['id']);
         $ann->content = $request->getParam('content');
@@ -150,10 +152,8 @@ final class AnnController extends BaseController
 
     /**
      * 后台删除公告
-     *
-     * @param array     $args
      */
-    public function delete(ServerRequest $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $ann = Ann::find($args['id']);
         if (! $ann->delete()) {
@@ -170,10 +170,8 @@ final class AnnController extends BaseController
 
     /**
      * 后台公告页面 AJAX
-     *
-     * @param array     $args
      */
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $anns = Ann::orderBy('id', 'asc')->get();
 

+ 0 - 9
src/Controllers/Admin/ApiController.php

@@ -12,9 +12,6 @@ use Slim\Http\ServerRequest;
 
 final class ApiController extends BaseController
 {
-    /**
-     * @param array     $args
-     */
     public function getNodeList(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->withJson([
@@ -23,9 +20,6 @@ final class ApiController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function getNodeInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node = Node::find($args['id']);
@@ -36,9 +30,6 @@ final class ApiController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function ping(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->withJson([

+ 27 - 12
src/Controllers/Admin/DetectController.php

@@ -10,12 +10,15 @@ use App\Models\DetectLog;
 use App\Models\DetectRule;
 use App\Utils\Telegram;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use Telegram\Bot\Exceptions\TelegramSDKException;
 
 final class DetectController extends BaseController
 {
-    public static $rule_details =
+    public static array $rule_details =
     [
         'field' => [
             'op' => '操作',
@@ -56,7 +59,7 @@ final class DetectController extends BaseController
         ],
     ];
 
-    public static $log_details =
+    public static array $log_details =
     [
         'field' => [
             'id' => '事件ID',
@@ -73,7 +76,7 @@ final class DetectController extends BaseController
         ],
     ];
 
-    public static $ban_details =
+    public static array $ban_details =
     [
         'field' => [
             'id' => '事件ID',
@@ -89,7 +92,10 @@ final class DetectController extends BaseController
         ],
     ];
 
-    public function detect(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function detect(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -98,7 +104,10 @@ final class DetectController extends BaseController
         );
     }
 
-    public function add(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws TelegramSDKException
+     */
+    public function add(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $rule = new DetectRule();
         $rule->name = $request->getParam('name');
@@ -120,7 +129,7 @@ final class DetectController extends BaseController
         ]);
     }
 
-    public function delete(ServerRequest $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $rule = DetectRule::find($id);
@@ -136,16 +145,22 @@ final class DetectController extends BaseController
         ]);
     }
 
-    public function log(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function log(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$log_details)
-                ->fetch('admin/log/detect_log.tpl')
+                ->fetch('admin/log/detect.tpl')
         );
     }
 
-    public function ban(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function ban(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -154,7 +169,7 @@ final class DetectController extends BaseController
         );
     }
 
-    public function ajaxRule(ServerRequest $request, Response $response, array $args)
+    public function ajaxRule(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $rules = DetectRule::orderBy('id', 'desc')->get();
 
@@ -169,7 +184,7 @@ final class DetectController extends BaseController
         ]);
     }
 
-    public function ajaxLog(ServerRequest $request, Response $response, array $args)
+    public function ajaxLog(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;
@@ -196,7 +211,7 @@ final class DetectController extends BaseController
         ]);
     }
 
-    public function ajaxBan(ServerRequest $request, Response $response, array $args)
+    public function ajaxBan(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;

+ 10 - 14
src/Controllers/Admin/InviteController.php

@@ -8,12 +8,14 @@ use App\Controllers\BaseController;
 use App\Models\Payback;
 use App\Models\User;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
 final class InviteController extends BaseController
 {
-    public static $details =
+    public static array $details =
     [
         'field' => [
             'id' => '事件ID',
@@ -58,9 +60,9 @@ final class InviteController extends BaseController
     /**
      * 后台邀请记录页面
      *
-     * @param array     $args
+     * @throws Exception
      */
-    public function invite(ServerRequest $request, Response $response, array $args)
+    public function invite(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -71,10 +73,8 @@ final class InviteController extends BaseController
 
     /**
      * 更改用户邀请者
-     *
-     * @param array     $args
      */
-    public function update(ServerRequest $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $userid = $request->getParam('userid');
 
@@ -85,7 +85,7 @@ final class InviteController extends BaseController
             ]);
         }
 
-        if (strpos($userid, '@') !== false) {
+        if (str_contains($userid, '@')) {
             $user = User::where('email', '=', $userid)->first();
         } else {
             $user = User::find((int) $userid);
@@ -109,10 +109,8 @@ final class InviteController extends BaseController
 
     /**
      * 为用户添加邀请次数
-     *
-     * @param array     $args
      */
-    public function add(ServerRequest $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $invite_num = $request->getParam('invite_num');
 
@@ -123,7 +121,7 @@ final class InviteController extends BaseController
             ]);
         }
 
-        if (strpos($request->getParam('userid'), '@') !== false) {
+        if (str_contains($request->getParam('userid'), '@')) {
             $user = User::where('email', '=', $request->getParam('userid'))->first();
         } else {
             $user = User::find((int) $request->getParam('userid'));
@@ -146,10 +144,8 @@ final class InviteController extends BaseController
 
     /**
      * 后台登录记录页面 AJAX
-     *
-     * @param array     $args
      */
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $paybacks = Payback::orderBy('id', 'desc')->get();
 

+ 13 - 14
src/Controllers/Admin/IpController.php

@@ -9,12 +9,15 @@ use App\Models\Ip;
 use App\Models\LoginIp;
 use App\Utils\QQWry;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function time;
 
 final class IpController extends BaseController
 {
-    public static $login_details =
+    public static array $login_details =
     [
         'field' => [
             'id' => '事件ID',
@@ -27,7 +30,7 @@ final class IpController extends BaseController
         ],
     ];
 
-    public static $ip_details =
+    public static array $ip_details =
     [
         'field' => [
             'id' => '事件ID',
@@ -44,9 +47,9 @@ final class IpController extends BaseController
     /**
      * 后台登录记录页面
      *
-     * @param array     $args
+     * @throws Exception
      */
-    public function login(ServerRequest $request, Response $response, array $args)
+    public function login(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -57,10 +60,8 @@ final class IpController extends BaseController
 
     /**
      * 后台登录记录页面 AJAX
-     *
-     * @param array     $args
      */
-    public function ajaxLogin(ServerRequest $request, Response $response, array $args)
+    public function ajaxLogin(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;
@@ -88,9 +89,9 @@ final class IpController extends BaseController
     /**
      * 后台在线 IP 页面
      *
-     * @param array     $args
+     * @throws Exception
      */
-    public function alive(ServerRequest $request, Response $response, array $args)
+    public function alive(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -101,17 +102,15 @@ final class IpController extends BaseController
 
     /**
      * 后台在线 IP 页面 AJAX
-     *
-     * @param array     $args
      */
-    public function ajaxAlive(ServerRequest $request, Response $response, array $args)
+    public function ajaxAlive(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;
         $draw = $request->getParam('draw');
 
-        $alives = Ip::where('datetime', '>=', \time() - 60)->orderBy('id', 'desc')->paginate($length, '*', '', $page);
-        $total = count(Ip::where('datetime', '>=', \time() - 60)->orderBy('id', 'desc')->get());
+        $alives = Ip::where('datetime', '>=', time() - 60)->orderBy('id', 'desc')->paginate($length, '*', '', $page);
+        $total = count(Ip::where('datetime', '>=', time() - 60)->orderBy('id', 'desc')->get());
 
         $QQWry = new QQWry();
         foreach ($alives as $alive) {

+ 11 - 18
src/Controllers/Admin/NodeController.php

@@ -7,9 +7,10 @@ namespace App\Controllers\Admin;
 use App\Controllers\BaseController;
 use App\Models\Node;
 use App\Models\Setting;
-use App\Utils\CloudflareDriver;
+use App\Services\CloudflareDriver;
 use App\Utils\Telegram;
 use App\Utils\Tools;
+use Cloudflare\API\Endpoints\EndpointException;
 use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
@@ -17,7 +18,7 @@ use Slim\Http\ServerRequest;
 
 final class NodeController extends BaseController
 {
-    public static $details = [
+    public static array $details = [
         'field' => [
             'op' => '操作',
             'id' => '节点ID',
@@ -34,7 +35,7 @@ final class NodeController extends BaseController
         ],
     ];
 
-    public static $update_field = [
+    public static array $update_field = [
         'name',
         'server',
         'mu_only',
@@ -52,7 +53,7 @@ final class NodeController extends BaseController
     /**
      * 后台节点页面
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -66,7 +67,7 @@ final class NodeController extends BaseController
     /**
      * 后台创建节点页面
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function create(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -80,7 +81,7 @@ final class NodeController extends BaseController
     /**
      * 后台添加节点
      *
-     * @param array     $args
+     * @throws EndpointException
      */
     public function add(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -164,12 +165,13 @@ final class NodeController extends BaseController
     /**
      * 后台编辑指定节点页面
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function edit(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $node = Node::find($id);
+
         return $response->write(
             $this->view()
                 ->assign('node', $node)
@@ -180,8 +182,6 @@ final class NodeController extends BaseController
 
     /**
      * 后台更新指定节点内容
-     *
-     * @param array     $args
      */
     public function update(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -250,10 +250,7 @@ final class NodeController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetNodePassword(ServerRequest $request, Response $response, array $args)
+    public function resetNodePassword(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $node = Node::find($id);
@@ -271,8 +268,6 @@ final class NodeController extends BaseController
 
     /**
      * 后台删除指定节点
-     *
-     * @param array     $args
      */
     public function delete(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -322,7 +317,7 @@ final class NodeController extends BaseController
             $new_node->name .= ' (副本)';
             $new_node->node_bandwidth = 0;
             $new_node->save();
-        } catch (\Exception $e) {
+        } catch (Exception $e) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => $e->getMessage(),
@@ -337,8 +332,6 @@ final class NodeController extends BaseController
 
     /**
      * 后台节点页面 AJAX
-     *
-     * @param array     $args
      */
     public function ajax(ServerRequest $request, Response $response, array $args): ResponseInterface
     {

+ 16 - 10
src/Controllers/Admin/Setting/BillingController.php

@@ -7,10 +7,13 @@ namespace App\Controllers\Admin\Setting;
 use App\Controllers\BaseController;
 use App\Models\Setting;
 use App\Services\Payment;
+use Exception;
+use function json_decode;
+use function json_encode;
 
 final class BillingController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         // 支付宝当面付
         'f2f_pay_app_id',
         'f2f_pay_pid',
@@ -48,6 +51,9 @@ final class BillingController extends BaseController
         'epay_usdt',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function billing($request, $response, $args)
     {
         $settings = [];
@@ -75,15 +81,15 @@ final class BillingController extends BaseController
     {
         $gateway_in_use = [];
 
-        foreach (array_values(self::returnGatewaysList()) as $value) {
-            $payment_enable = $request->getParam("${value}");
+        foreach (self::returnGatewaysList() as $value) {
+            $payment_enable = $request->getParam($value);
             if ($payment_enable === 'true') {
-                \array_push($gateway_in_use, $value);
+                $gateway_in_use[] = $value;
             }
         }
 
         $gateway = Setting::where('item', '=', 'payment_gateway')->first();
-        $gateway->value = \json_encode($gateway_in_use);
+        $gateway->value = json_encode($gateway_in_use);
 
         if (! $gateway->save()) {
             return $response->withJson([
@@ -98,15 +104,15 @@ final class BillingController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }
@@ -117,7 +123,7 @@ final class BillingController extends BaseController
         ]);
     }
 
-    public function returnGatewaysList()
+    public function returnGatewaysList(): array
     {
         $result = [];
 
@@ -131,6 +137,6 @@ final class BillingController extends BaseController
     public function returnActiveGateways()
     {
         $payment_gateways = Setting::where('item', '=', 'payment_gateway')->first();
-        return \json_decode($payment_gateways->value);
+        return json_decode($payment_gateways->value);
     }
 }

+ 9 - 4
src/Controllers/Admin/Setting/CaptchaController.php

@@ -6,10 +6,12 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class CaptchaController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'captcha_provider',
         'enable_reg_captcha',
         'enable_login_captcha',
@@ -23,6 +25,9 @@ final class CaptchaController extends BaseController
         'geetest_key',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function captcha($request, $response, $args)
     {
         $settings = [];
@@ -52,15 +57,15 @@ final class CaptchaController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 12 - 8
src/Controllers/Admin/Setting/EmailController.php

@@ -7,10 +7,13 @@ namespace App\Controllers\Admin\Setting;
 use App\Controllers\BaseController;
 use App\Models\Setting;
 use App\Services\Mail;
+use Exception;
+use Throwable;
+use function json_encode;
 
 final class EmailController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'mail_driver',
         // SMTP
         'smtp_host',
@@ -41,6 +44,9 @@ final class EmailController extends BaseController
         'postal_name',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function email($request, $response, $args)
     {
         $settings = [];
@@ -70,15 +76,15 @@ final class EmailController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }
@@ -97,11 +103,9 @@ final class EmailController extends BaseController
             Mail::send(
                 $to,
                 '测试邮件',
-                'auth/test.tpl',
-                [],
-                []
+                'auth/test.tpl'
             );
-        } catch (\Throwable $e) {
+        } catch (Throwable $e) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '测试邮件发送失败',

+ 9 - 4
src/Controllers/Admin/Setting/FeatureController.php

@@ -6,15 +6,20 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class FeatureController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'display_media',
         'display_subscribe_log',
         'display_detect_log',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function feature($request, $response, $args)
     {
         $settings = [];
@@ -44,15 +49,15 @@ final class FeatureController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 9 - 4
src/Controllers/Admin/Setting/ImController.php

@@ -6,10 +6,12 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class ImController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'telegram_add_node',
         'telegram_add_node_text',
         'telegram_update_node',
@@ -48,6 +50,9 @@ final class ImController extends BaseController
         'telegram_general_terms',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function im($request, $response, $args)
     {
         $settings = [];
@@ -77,15 +82,15 @@ final class ImController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 9 - 4
src/Controllers/Admin/Setting/RefController.php

@@ -6,10 +6,12 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class RefController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'invitation_to_register_balance_reward',
         'invitation_to_register_traffic_reward',
         'invitation_mode',
@@ -20,6 +22,9 @@ final class RefController extends BaseController
         'rebate_time_range_limit',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function ref($request, $response, $args)
     {
         $settings = [];
@@ -49,15 +54,15 @@ final class RefController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 9 - 4
src/Controllers/Admin/Setting/RegController.php

@@ -6,10 +6,12 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class RegController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'reg_mode',
         'reg_email_verify',
         'email_verify_ttl',
@@ -35,6 +37,9 @@ final class RegController extends BaseController
         'reg_forbidden_port',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function reg($request, $response, $args)
     {
         $settings = [];
@@ -64,15 +69,15 @@ final class RegController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 9 - 4
src/Controllers/Admin/Setting/SupportController.php

@@ -6,10 +6,12 @@ namespace App\Controllers\Admin\Setting;
 
 use App\Controllers\BaseController;
 use App\Models\Setting;
+use Exception;
+use function json_encode;
 
 final class SupportController extends BaseController
 {
-    public static $update_field = [
+    public static array $update_field = [
         'live_chat',
         'tawk_id',
         'crisp_id',
@@ -22,6 +24,9 @@ final class SupportController extends BaseController
         'admin_contact3',
     ];
 
+    /**
+     * @throws Exception
+     */
     public function support($request, $response, $args)
     {
         $settings = [];
@@ -51,15 +56,15 @@ final class SupportController extends BaseController
             $setting = Setting::where('item', '=', $item)->first();
 
             if ($setting->type === 'array') {
-                $setting->value = \json_encode($request->getParam("${item}"));
+                $setting->value = json_encode($request->getParam($item));
             } else {
-                $setting->value = $request->getParam("${item}");
+                $setting->value = $request->getParam($item);
             }
 
             if (! $setting->save()) {
                 return $response->withJson([
                     'ret' => 0,
-                    'msg' => "保存 ${item} 时出错",
+                    'msg' => "保存 {$item} 时出错",
                 ]);
             }
         }

+ 0 - 370
src/Controllers/Admin/ShopController.php

@@ -1,370 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Controllers\Admin;
-
-use App\Controllers\BaseController;
-use App\Models\Bought;
-use App\Models\Shop;
-use App\Utils\ResponseHelper;
-use Slim\Http\Response;
-use Slim\Http\ServerRequest;
-
-final class ShopController extends BaseController
-{
-    /**
-     * 后台商品页面
-     *
-     * @param array     $args
-     */
-    public function index(ServerRequest $request, Response $response, array $args)
-    {
-        return $response->write(
-            $this->view()
-                ->assign('table_config', ResponseHelper::buildTableConfig([
-                    'op' => '操作',
-                    'id' => 'ID',
-                    'name' => '商品名称',
-                    'price' => '价格',
-                    'content' => '商品内容',
-                    'auto_renew' => '自动续费',
-                    'auto_reset_bandwidth' => '续费时是否重置流量',
-                    'status' => '状态',
-                    'period_sales' => '周期销量',
-                ], 'shop/ajax'))
-                ->fetch('admin/shop/index.tpl')
-        );
-    }
-
-    /**
-     * 后台创建新商品页面
-     *
-     * @param array     $args
-     */
-    public function create(ServerRequest $request, Response $response, array $args)
-    {
-        return $response->write(
-            $this->view()
-                ->fetch('admin/shop/create.tpl')
-        );
-    }
-
-    /**
-     * 后台添加新商品
-     *
-     * @param array     $args
-     */
-    public function add(ServerRequest $request, Response $response, array $args)
-    {
-        $shop = new Shop();
-        $shop->name = $request->getParam('name');
-        $shop->price = $request->getParam('price');
-        $shop->auto_renew = $request->getParam('auto_renew');
-        $shop->auto_reset_bandwidth = $request->getParam('auto_reset_bandwidth');
-
-        $content = [];
-        if ($request->getParam('bandwidth') !== 0) {
-            $content['bandwidth'] = $request->getParam('bandwidth');
-        }
-
-        if ($request->getParam('expire') !== 0) {
-            $content['expire'] = $request->getParam('expire');
-        }
-
-        if ($request->getParam('class') !== 0 && $request->getParam('class_expire') !== 0) {
-            $content['class'] = $request->getParam('class');
-            $content['class_expire'] = $request->getParam('class_expire');
-        }
-
-        if ($request->getParam('reset') !== 0) {
-            $content['reset'] = $request->getParam('reset');
-        }
-
-        if ($request->getParam('reset_value') !== 0) {
-            $content['reset_value'] = $request->getParam('reset_value');
-        }
-
-        if ($request->getParam('reset_exp') !== 0) {
-            $content['reset_exp'] = $request->getParam('reset_exp');
-        }
-
-        if ($request->getParam('traffic_package') !== 0) {
-            $content['traffic_package'] = $request->getParam('traffic_package');
-        }
-
-        $content['speedlimit'] = $request->getParam('speedlimit');
-
-        $content['connector'] = $request->getParam('connector');
-
-        if ($request->getParam('content_extra') !== '') {
-            $content['content_extra'] = $request->getParam('content_extra');
-        }
-
-        $shop->content = $content;
-
-        if (! $shop->save()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '添加失败',
-            ]);
-        }
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '添加成功',
-        ]);
-    }
-
-    /**
-     * 后台编辑指定商品
-     *
-     * @param array     $args
-     */
-    public function edit(ServerRequest $request, Response $response, array $args)
-    {
-        $id = $args['id'];
-        $shop = Shop::find($id);
-        return $response->write(
-            $this->view()
-                ->assign('shop', $shop)
-                ->fetch('admin/shop/edit.tpl')
-        );
-    }
-
-    /**
-     * 后台更新指定商品内容
-     *
-     * @param array     $args
-     */
-    public function update(ServerRequest $request, Response $response, array $args)
-    {
-        $id = $args['id'];
-        $shop = Shop::find($id);
-
-        $shop->name = $request->getParam('name');
-        $shop->price = $request->getParam('price');
-        $shop->auto_renew = $request->getParam('auto_renew');
-
-        if ($shop->auto_reset_bandwidth === 1 && $request->getParam('auto_reset_bandwidth') === 0) {
-            $boughts = Bought::where('shopid', $id)->get();
-
-            foreach ($boughts as $bought) {
-                $bought->renew = 0;
-                $bought->save();
-            }
-        }
-
-        $shop->auto_reset_bandwidth = $request->getParam('auto_reset_bandwidth');
-        $shop->status = 1;
-
-        $content = [];
-        if ($request->getParam('bandwidth') !== 0) {
-            $content['bandwidth'] = $request->getParam('bandwidth');
-        }
-
-        if ($request->getParam('expire') !== 0) {
-            $content['expire'] = $request->getParam('expire');
-        }
-
-        if ($request->getParam('class') !== 0 && $request->getParam('class_expire') !== 0) {
-            $content['class'] = $request->getParam('class');
-            $content['class_expire'] = $request->getParam('class_expire');
-        }
-
-        if ($request->getParam('reset') !== 0) {
-            $content['reset'] = $request->getParam('reset');
-        }
-
-        if ($request->getParam('reset_value') !== 0) {
-            $content['reset_value'] = $request->getParam('reset_value');
-        }
-
-        if ($request->getParam('reset_exp') !== 0) {
-            $content['reset_exp'] = $request->getParam('reset_exp');
-        }
-
-        if ($request->getParam('traffic_package') !== 0) {
-            $content['traffic_package'] = $request->getParam('traffic_package');
-        }
-
-        $content['speedlimit'] = $request->getParam('speedlimit');
-        $content['connector'] = $request->getParam('connector');
-        if ($request->getParam('content_extra') !== '') {
-            $content['content_extra'] = $request->getParam('content_extra');
-        }
-        $shop->content = $content;
-        if (! $shop->save()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '保存失败',
-            ]);
-        }
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '保存成功',
-        ]);
-    }
-
-    /**
-     * 后台下架指定商品
-     *
-     * @param array     $args
-     */
-    public function deleteGet(ServerRequest $request, Response $response, array $args)
-    {
-        $id = $request->getParam('id');
-        $shop = Shop::find($id);
-        $shop->status = 0;
-        if (! $shop->save()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '下架失败',
-            ]);
-        }
-        $boughts = Bought::where('shopid', $id)->get();
-        foreach ($boughts as $bought) {
-            $bought->renew = 0;
-            $bought->save();
-        }
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '下架成功',
-        ]);
-    }
-
-    /**
-     * 后台购买记录页面
-     *
-     * @param array     $args
-     */
-    public function bought(ServerRequest $request, Response $response, array $args)
-    {
-        return $response->write(
-            $this->view()
-                ->assign('table_config', ResponseHelper::buildTableConfig([
-                    'op' => '操作',
-                    'id' => 'ID',
-                    'datetime' => '购买日期',
-                    'content' => '内容',
-                    'price' => '价格',
-                    'userid' => '用户ID',
-                    'user_name' => '用户名',
-                    'renew' => '自动续费时间',
-                    'auto_reset_bandwidth' => '续费时是否重置流量',
-                ], 'bought/ajax'))
-                ->fetch('admin/shop/bought.tpl')
-        );
-    }
-
-    /**
-     * 后台退订指定购买记录的自动续费
-     *
-     * @param array     $args
-     */
-    public function deleteBoughtGet(ServerRequest $request, Response $response, array $args)
-    {
-        $id = $request->getParam('id');
-        $shop = Bought::find($id);
-        $shop->renew = 0;
-        if (! $shop->save()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '退订失败',
-            ]);
-        }
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '退订成功',
-        ]);
-    }
-
-    /**
-     * 后台商品页面 AJAX
-     *
-     * @param array     $args
-     */
-    public function ajaxShop(ServerRequest $request, Response $response, array $args)
-    {
-        $query = Shop::getTableDataFromAdmin(
-            $request,
-            static function (&$order_field): void {
-                if (\in_array($order_field, ['op', 'period_sales'])) {
-                    $order_field = 'id';
-                }
-            }
-        );
-
-        $data = [];
-        foreach ($query['datas'] as $value) {
-            /** @var Shop $value */
-
-            $tempdata = [];
-            $tempdata['op'] = '<a class="btn btn-brand" href="/admin/shop/' . $value->id . '/edit">编辑</a> <a class = "btn btn-brand-accent" ' . ($value->status === 0 ? 'disabled' : 'id="row_delete_' . $value->id . '" href="javascript:void(0);" onClick="delete_modal_show(\'' . $value->id . '\')"') . '>下架</a>';
-            $tempdata['id'] = $value->id;
-            $tempdata['name'] = $value->name;
-            $tempdata['price'] = $value->price;
-            $tempdata['content'] = $value->content();
-            $tempdata['auto_renew'] = $value->autoRenew();
-            $tempdata['auto_reset_bandwidth'] = $value->autoResetBandwidthString();
-            $tempdata['status'] = $value->status();
-            $tempdata['period_sales'] = $value->getSales();
-
-            $data[] = $tempdata;
-        }
-
-        return $response->withJson([
-            'draw' => $request->getParam('draw'),
-            'recordsTotal' => Shop::count(),
-            'recordsFiltered' => $query['count'],
-            'data' => $data,
-        ]);
-    }
-
-    /**
-     * 后台购买记录 AJAX
-     *
-     * @param array     $args
-     */
-    public function ajaxBought(ServerRequest $request, Response $response, array $args)
-    {
-        $query = Bought::getTableDataFromAdmin(
-            $request,
-            static function (&$order_field): void {
-                if (\in_array($order_field, ['op'])) {
-                    $order_field = 'id';
-                }
-                if (\in_array($order_field, ['content', 'auto_reset_bandwidth'])) {
-                    $order_field = 'shopid';
-                }
-                if (\in_array($order_field, ['user_name'])) {
-                    $order_field = 'userid';
-                }
-            }
-        );
-
-        $data = [];
-        foreach ($query['datas'] as $value) {
-            /** @var Bought $value */
-
-            $tempdata = [];
-            $tempdata['op'] = '<a class="btn btn-brand-accent" ' . ($value->renew === 0 ? 'disabled' : ' id="row_delete_' . $value->id . '" href="javascript:void(0);" onClick="delete_modal_show(\'' . $value->id . '\')"') . '>中止</a>';
-            $tempdata['id'] = $value->id;
-            $tempdata['datetime'] = $value->datetime();
-            $tempdata['content'] = $value->content();
-            $tempdata['price'] = $value->price;
-            $tempdata['userid'] = $value->userid;
-            $tempdata['user_name'] = $value->userName();
-            $tempdata['renew'] = $value->renew();
-            $tempdata['auto_reset_bandwidth'] = $value->autoResetBandwidthString();
-
-            $data[] = $tempdata;
-        }
-
-        return $response->withJson([
-            'draw' => $request->getParam('draw'),
-            'recordsTotal' => Bought::count(),
-            'recordsFiltered' => $query['count'],
-            'data' => $data,
-        ]);
-    }
-}

+ 3 - 4
src/Controllers/Admin/SubscribeLogController.php

@@ -7,13 +7,14 @@ namespace App\Controllers\Admin;
 use App\Controllers\BaseController;
 use App\Models\UserSubscribeLog;
 use App\Utils\QQWry;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
 final class SubscribeLogController extends BaseController
 {
-    public static $details =
+    public static array $details =
     [
         'field' => [
             'id' => '事件ID',
@@ -31,7 +32,7 @@ final class SubscribeLogController extends BaseController
     /**
      * 后台订阅记录页面
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -44,8 +45,6 @@ final class SubscribeLogController extends BaseController
 
     /**
      * 后台订阅记录页面 AJAX
-     *
-     * @param array     $args
      */
     public function ajaxSubscribeLog(ServerRequest $request, Response $response, array $args): ResponseInterface
     {

+ 17 - 19
src/Controllers/Admin/TicketController.php

@@ -8,13 +8,19 @@ use App\Controllers\BaseController;
 use App\Models\Ticket;
 use App\Models\User;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function array_merge;
+use function json_decode;
+use function json_encode;
+use function time;
 
 final class TicketController extends BaseController
 {
-    public static $details =
+    public static array $details =
     [
         'field' => [
             'op' => '操作',
@@ -30,9 +36,9 @@ final class TicketController extends BaseController
     /**
      * 后台工单页面
      *
-     * @param array     $args
+     * @throws Exception
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -43,8 +49,6 @@ final class TicketController extends BaseController
 
     /**
      * 后台更新工单内容
-     *
-     * @param array     $args
      */
     public function update(ServerRequest $request, Response $response, array $args)
     {
@@ -66,13 +70,13 @@ final class TicketController extends BaseController
 
         $antiXss = new AntiXSS();
 
-        $content_old = \json_decode($ticket->content, true);
+        $content_old = json_decode($ticket->content, true);
         $content_new = [
             [
                 'comment_id' => $content_old[count($content_old) - 1]['comment_id'] + 1,
                 'commenter_name' => 'Admin',
                 'comment' => $antiXss->xss_clean($comment),
-                'datetime' => \time(),
+                'datetime' => time(),
             ],
         ];
 
@@ -86,7 +90,7 @@ final class TicketController extends BaseController
             []
         );
 
-        $ticket->content = \json_encode(\array_merge($content_old, $content_new));
+        $ticket->content = json_encode(array_merge($content_old, $content_new));
         $ticket->status = 'open_wait_user';
         $ticket->save();
 
@@ -99,13 +103,13 @@ final class TicketController extends BaseController
     /**
      * 后台查看指定工单
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function ticketView(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->first();
-        $comments = \json_decode($ticket->content, true);
+        $comments = json_decode($ticket->content, true);
 
         if ($ticket === null) {
             return $response->withStatus(302)->withHeader('Location', '/user/ticket');
@@ -122,10 +126,8 @@ final class TicketController extends BaseController
 
     /**
      * 后台关闭工单
-     *
-     * @param array     $args
      */
-    public function close(ServerRequest $request, Response $response, array $args)
+    public function close(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->first();
@@ -158,10 +160,8 @@ final class TicketController extends BaseController
 
     /**
      * 后台删除工单
-     *
-     * @param array     $args
      */
-    public function delete(ServerRequest $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         Ticket::where('id', '=', $id)->delete();
@@ -174,10 +174,8 @@ final class TicketController extends BaseController
 
     /**
      * 后台工单页面 Ajax
-     *
-     * @param array     $args
      */
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $tickets = Ticket::orderBy('id', 'desc')->get();
 

+ 3 - 4
src/Controllers/Admin/TrafficLogController.php

@@ -7,13 +7,14 @@ namespace App\Controllers\Admin;
 use App\Controllers\BaseController;
 use App\Models\UserHourlyUsage;
 use App\Utils\Tools;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
 final class TrafficLogController extends BaseController
 {
-    public static $details =
+    public static array $details =
     [
         'field' => [
             'id' => '记录ID',
@@ -27,7 +28,7 @@ final class TrafficLogController extends BaseController
     /**
      * 后台流量记录页面
      *
-     * @param array     $args
+     * @throws Exception
      */
     public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -40,8 +41,6 @@ final class TrafficLogController extends BaseController
 
     /**
      * 后台流量记录页面 AJAX
-     *
-     * @param array     $args
      */
     public function ajaxTrafficLog(ServerRequest $request, Response $response, array $args): ResponseInterface
     {

+ 22 - 33
src/Controllers/Admin/UserController.php

@@ -8,16 +8,18 @@ use App\Controllers\AuthController;
 use App\Controllers\BaseController;
 use App\Models\User;
 use App\Services\Auth;
-use App\Utils\Check;
 use App\Utils\Cookie;
 use App\Utils\Hash;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function time;
 
 final class UserController extends BaseController
 {
-    public static $details = [
+    public static array $details = [
         'field' => [
             'op' => '操作',
             'id' => '用户ID',
@@ -60,7 +62,7 @@ final class UserController extends BaseController
         ],
     ];
 
-    public static $update_field = [
+    public static array $update_field = [
         'email',
         'user_name',
         'remark',
@@ -90,9 +92,9 @@ final class UserController extends BaseController
     ];
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -101,10 +103,7 @@ final class UserController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
-    public function createNewUser(ServerRequest $request, Response $response, array $args)
+    public function createNewUser(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $email = $request->getParam('email');
         $ref_by = $request->getParam('ref_by');
@@ -113,14 +112,14 @@ final class UserController extends BaseController
 
         try {
             if ($email === '') {
-                throw new \Exception('请填写邮箱');
+                throw new Exception('请填写邮箱');
             }
-            if (! Check::isEmailLegal($email)) {
-                throw new \Exception('邮箱格式不正确');
+            if (! Tools::isEmailLegal($email)) {
+                throw new Exception('邮箱格式不正确');
             }
             $exist = User::where('email', $email)->first();
             if ($exist !== null) {
-                throw new \Exception('此邮箱已注册');
+                throw new Exception('此邮箱已注册');
             }
             if ($password === '') {
                 $password = Tools::genRandomChar(16);
@@ -131,7 +130,7 @@ final class UserController extends BaseController
                 $user->ref_by = (int) $ref_by;
                 $user->save();
             }
-        } catch (\Exception $e) {
+        } catch (Exception $e) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => $e->getMessage(),
@@ -145,11 +144,12 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function edit(ServerRequest $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $user = User::find($args['id']);
+
         return $response->write(
             $this->view()
                 ->assign('update_field', self::$update_field)
@@ -158,10 +158,7 @@ final class UserController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
-    public function update(ServerRequest $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $user = User::find($id);
@@ -210,10 +207,8 @@ final class UserController extends BaseController
             'msg' => '修改成功',
         ]);
     }
-    /**
-     * @param array     $args
-     */
-    public function delete(ServerRequest $request, Response $response, array $args)
+
+    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $user = User::find((int) $id);
@@ -231,16 +226,13 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function changetouser(ServerRequest $request, Response $response, array $args)
+    public function changetouser(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $userid = $request->getParam('userid');
         $adminid = $request->getParam('adminid');
         $user = User::find($userid);
         $admin = User::find($adminid);
-        $expire_in = \time() + 60 * 60;
+        $expire_in = time() + 60 * 60;
 
         if (! $admin->is_admin || ! $user || ! Auth::getUser()->isLogin) {
             return $response->withJson([
@@ -269,10 +261,7 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $users = User::orderBy('id', 'desc')->get();
 

+ 3 - 2
src/Controllers/AdminController.php

@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace App\Controllers;
 
 use App\Services\Analytics;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
@@ -16,9 +17,9 @@ final class AdminController extends BaseController
     /**
      * 后台首页
      *
-     * @param array     $args
+     * @noinspection PhpUnhandledExceptionInspection
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()

+ 43 - 38
src/Controllers/AuthController.php

@@ -11,17 +11,18 @@ use App\Models\User;
 use App\Services\Auth;
 use App\Services\Captcha;
 use App\Services\Mail;
-use App\Utils\Check;
 use App\Utils\Hash;
 use App\Utils\ResponseHelper;
 use App\Utils\Tools;
 use Exception;
+use Psr\Http\Client\ClientExceptionInterface;
 use Psr\Http\Message\ResponseInterface;
 use Ramsey\Uuid\Uuid;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use Vectorface\GoogleAuthenticator;
 use voku\helper\AntiXSS;
+use function time;
 
 /**
  *  AuthController
@@ -29,7 +30,7 @@ use voku\helper\AntiXSS;
 final class AuthController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function login(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -45,10 +46,7 @@ final class AuthController extends BaseController
             ->fetch('auth/login.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function loginHandle(ServerRequest $request, Response $response, array $args)
+    public function loginHandle(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         if (Setting::obtain('enable_login_captcha') === true) {
             $ret = Captcha::verify($request->getParams());
@@ -109,9 +107,9 @@ final class AuthController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function register(ServerRequest $request, Response $response, $next)
+    public function register(ServerRequest $request, Response $response, $next): Response|ResponseInterface
     {
         $captcha = [];
 
@@ -134,10 +132,7 @@ final class AuthController extends BaseController
             ->fetch('auth/register.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function sendVerify(ServerRequest $request, Response $response, $next)
+    public function sendVerify(ServerRequest $request, Response $response, $next): Response|ResponseInterface
     {
         if (Setting::obtain('reg_email_verify')) {
             $antiXss = new AntiXSS();
@@ -149,7 +144,7 @@ final class AuthController extends BaseController
             }
 
             // check email format
-            $check_res = Check::isEmailLegal($email);
+            $check_res = Tools::isEmailLegal($email);
             if ($check_res['ret'] === 0) {
                 return $response->withJson($check_res);
             }
@@ -160,14 +155,14 @@ final class AuthController extends BaseController
             }
 
             $ipcount = EmailVerify::where('ip', '=', $_SERVER['REMOTE_ADDR'])
-                ->where('expire_in', '>', \time())
+                ->where('expire_in', '>', time())
                 ->count();
             if ($ipcount > Setting::obtain('email_verify_ip_limit')) {
                 return ResponseHelper::error($response, '此IP请求次数过多');
             }
 
             $mailcount = EmailVerify::where('email', '=', $email)
-                ->where('expire_in', '>', \time())
+                ->where('expire_in', '>', time())
                 ->count();
             if ($mailcount > Setting::obtain('email_verify_email_limit')) {
                 return ResponseHelper::error($response, '此邮箱请求次数过多');
@@ -175,7 +170,7 @@ final class AuthController extends BaseController
 
             $code = Tools::genRandomChar(6);
             $ev = new EmailVerify();
-            $ev->expire_in = \time() + Setting::obtain('email_verify_ttl');
+            $ev->expire_in = time() + Setting::obtain('email_verify_ttl');
             $ev->ip = $_SERVER['REMOTE_ADDR'];
             $ev->email = $email;
             $ev->code = $code;
@@ -188,11 +183,10 @@ final class AuthController extends BaseController
                     'auth/verify.tpl',
                     [
                         'code' => $code,
-                        'expire' => date('Y-m-d H:i:s', \time() + Setting::obtain('email_verify_ttl')),
-                    ],
-                    []
+                        'expire' => date('Y-m-d H:i:s', time() + Setting::obtain('email_verify_ttl')),
+                    ]
                 );
-            } catch (Exception $e) {
+            } catch (Exception | ClientExceptionInterface $e) {
                 return ResponseHelper::error($response, '邮件发送失败,请联系网站管理员。');
             }
 
@@ -202,13 +196,26 @@ final class AuthController extends BaseController
     }
 
     /**
-     * @param ServerRequest   $request
-     * @param Response  $response
-     * @param array     $args
+     * @param Response $response
+     * @param $name
+     * @param $email
+     * @param $passwd
+     * @param $code
+     * @param $imtype
+     * @param $imvalue
+     * @param $telegram_id
+     * @param $money
+     * @param $is_admin_reg
+     *
+     * @return ResponseInterface
+     *
+     * @throws Exception
      */
-    public static function registerHelper($response, $name, $email, $passwd, $code, $imtype, $imvalue, $telegram_id, $money, $is_admin_reg)
+    public static function registerHelper(Response $response, $name, $email, $passwd, $code, $imtype, $imvalue, $telegram_id, $money, $is_admin_reg): ResponseInterface
     {
         $user_invite = InviteCode::where('code', $code)->first();
+        $gift_user = null;
+
         if ($user_invite === null) {
             if (Setting::obtain('reg_mode') === 'invite') {
                 return ResponseHelper::error($response, '邀请码无效');
@@ -228,7 +235,7 @@ final class AuthController extends BaseController
         // do reg user
         $user = new User();
         $antiXss = new AntiXSS();
-        $current_timestamp = \time();
+        $current_timestamp = time();
 
         $user->user_name = $antiXss->xss_clean($name);
         $user->email = $antiXss->xss_clean($email);
@@ -285,11 +292,11 @@ final class AuthController extends BaseController
         $user->ga_token = $secret;
         $user->ga_enable = 0;
 
-        $user->class_expire = date('Y-m-d H:i:s', \time() + $configs['sign_up_for_class_time'] * 86400);
+        $user->class_expire = date('Y-m-d H:i:s', time() + $configs['sign_up_for_class_time'] * 86400);
         $user->class = $configs['sign_up_for_class'];
         $user->node_connector = $configs['connection_device_limit'];
         $user->node_speedlimit = $configs['connection_rate_limit'];
-        $user->expire_in = date('Y-m-d H:i:s', \time() + $configs['sign_up_for_free_time'] * 86400);
+        $user->expire_in = date('Y-m-d H:i:s', time() + $configs['sign_up_for_free_time'] * 86400);
         $user->reg_date = date('Y-m-d H:i:s');
         $user->reg_ip = $_SERVER['REMOTE_ADDR'];
         $user->theme = $_ENV['theme'];
@@ -317,10 +324,7 @@ final class AuthController extends BaseController
         return ResponseHelper::error($response, '未知错误');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function registerHandle(ServerRequest $request, Response $response, array $args)
+    public function registerHandle(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         if (Setting::obtain('reg_mode') === 'close') {
             return ResponseHelper::error($response, '未开放注册。');
@@ -361,7 +365,7 @@ final class AuthController extends BaseController
         }
 
         // check email format
-        $check_res = Check::isEmailLegal($email);
+        $check_res = Tools::isEmailLegal($email);
         if ($check_res['ret'] === 0) {
             return $response->withJson($check_res);
         }
@@ -375,7 +379,7 @@ final class AuthController extends BaseController
             $email_code = trim($antiXss->xss_clean($request->getParam('emailcode')));
             $mailcount = EmailVerify::where('email', '=', $email)
                 ->where('code', '=', $email_code)
-                ->where('expire_in', '>', \time())
+                ->where('expire_in', '>', time())
                 ->first();
             if ($mailcount === null) {
                 return ResponseHelper::error($response, '您的邮箱验证码不正确');
@@ -396,13 +400,14 @@ final class AuthController extends BaseController
             EmailVerify::where('email', $email)->delete();
         }
 
-        return $this->registerHelper($response, $name, $email, $passwd, $code, $imtype, $imvalue, 0, 0, 0);
+        try {
+            return $this->registerHelper($response, $name, $email, $passwd, $code, $imtype, $imvalue, 0, 0, 0);
+        } catch (Exception $e) {
+            return ResponseHelper::error($response, $e->getMessage());
+        }
     }
 
-    /**
-     * @param array     $args
-     */
-    public function logout(ServerRequest $request, Response $response, $next)
+    public function logout(ServerRequest $request, Response $response, $next): Response
     {
         Auth::logout();
         return $response->withStatus(302)

+ 2 - 2
src/Controllers/BaseController.php

@@ -17,12 +17,12 @@ abstract class BaseController
     /**
      * @var Smarty
      */
-    protected $view;
+    protected Smarty $view;
 
     /**
      * @var User
      */
-    protected $user;
+    protected User $user;
 
     /**
      * Construct page renderer

+ 12 - 8
src/Controllers/HomeController.php

@@ -7,9 +7,11 @@ namespace App\Controllers;
 use App\Models\InviteCode;
 use App\Services\Auth;
 use App\Utils\Telegram\Process;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use Telegram\Bot\Exceptions\TelegramSDKException;
 
 /**
  *  HomeController
@@ -17,7 +19,7 @@ use Slim\Http\ServerRequest;
 final class HomeController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -25,16 +27,17 @@ final class HomeController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function code(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $codes = InviteCode::where('user_id', '=', '0')->take(10)->get();
+
         return $response->write($this->view()->assign('codes', $codes)->fetch('code.tpl'));
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function tos(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -42,7 +45,7 @@ final class HomeController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function staff(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -50,11 +53,12 @@ final class HomeController extends BaseController
         if (! $user->isLogin) {
             return $response->withStatus(404)->write($this->view()->fetch('404.tpl'));
         }
+
         return $response->write($this->view()->fetch('staff.tpl'));
     }
 
     /**
-     * @param array     $args
+     * @throws TelegramSDKException
      */
     public function telegram(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -69,7 +73,7 @@ final class HomeController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function page404(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -77,7 +81,7 @@ final class HomeController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function page405(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
@@ -85,7 +89,7 @@ final class HomeController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function page500(ServerRequest $request, Response $response, array $args): ResponseInterface
     {

+ 60 - 67
src/Controllers/LinkController.php

@@ -9,6 +9,10 @@ use App\Models\Node;
 use App\Models\UserSubscribeLog;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function array_key_exists;
+use function base64_encode;
+use function json_decode;
+use function json_encode;
 
 /**
  *  LinkController
@@ -40,6 +44,7 @@ final class LinkController extends BaseController
             ]);
         }
 
+        $sub_type = '';
         $sub_info = [];
 
         if (isset($params['clash']) && $params['clash'] === '1') {
@@ -69,10 +74,6 @@ final class LinkController extends BaseController
 
         if (isset($params['sub'])) {
             switch ($params['sub']) {
-                case '2':
-                    $sub_type = 'ss';
-                    $sub_info = self::getSS($user);
-                    break;
                 case '3':
                     $sub_type = 'v2ray';
                     $sub_info = self::getV2Ray($user);
@@ -117,18 +118,16 @@ final class LinkController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
-            switch ($node_raw->sort) {
-                case '0':
-                    $links .= \base64_encode($user->method . ':' . $user->passwd . '@' . $server . ':' . $user->port) . '#' .
+            if ($node_raw->sort === '0') {
+                $links .= base64_encode($user->method . ':' . $user->passwd . '@' . $server . ':' . $user->port) . '#' .
                     $node_raw->name . PHP_EOL;
-                    break;
             }
         }
 
@@ -149,22 +148,20 @@ final class LinkController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
-            switch ($node_raw->sort) {
-                case '0':
-                    $plugin = $node_custom_config['plugin'] ?? '';
-                    $plugin_option = $node_custom_config['plugin_option'] ?? '';
+            if ($node_raw->sort === '0') {
+                $plugin = $node_custom_config['plugin'] ?? '';
+                $plugin_option = $node_custom_config['plugin_option'] ?? '';
 
-                    $links .= $user->method . ':' . $user->passwd . '@' . $server . ':' .
+                $links .= $user->method . ':' . $user->passwd . '@' . $server . ':' .
                     $user->port . '/?plugin=' . $plugin . '&' . $plugin_option . '#' .
                     $node_raw->name . PHP_EOL;
-                    break;
             }
         }
 
@@ -184,41 +181,39 @@ final class LinkController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
-            switch ($node_raw->sort) {
-                case '11':
-                    $v2_port = $node_custom_config['v2_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
-                    //默認值有問題的請懂 V2 怎麽用的人來改一改。
-                    $alter_id = $node_custom_config['alter_id'] ?? '0';
-                    $security = $node_custom_config['security'] ?? 'none';
-                    $network = $node_custom_config['network'] ?? '';
-                    $header = $node_custom_config['header'] ?? ['type' => 'none'];
-                    $header_type = $header['type'] ?? '';
-                    $host = $node_custom_config['host'] ?? '';
-                    $path = $node_custom_config['path'] ?? '/';
-
-                    $v2rayn_array = [
-                        'v' => '2',
-                        'ps' => $node_raw->name,
-                        'add' => $server,
-                        'port' => $v2_port,
-                        'id' => $user->uuid,
-                        'aid' => $alter_id,
-                        'net' => $network,
-                        'type' => $header_type,
-                        'host' => $host,
-                        'path' => $path,
-                        'tls' => $security,
-                    ];
-
-                    $links .= 'vmess://' . \base64_encode(\json_encode($v2rayn_array)) . PHP_EOL;
-                    break;
+            if ($node_raw->sort === '11') {
+                $v2_port = $node_custom_config['v2_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
+                //默認值有問題的請懂 V2 怎麽用的人來改一改。
+                $alter_id = $node_custom_config['alter_id'] ?? '0';
+                $security = $node_custom_config['security'] ?? 'none';
+                $network = $node_custom_config['network'] ?? '';
+                $header = $node_custom_config['header'] ?? ['type' => 'none'];
+                $header_type = $header['type'] ?? '';
+                $host = $node_custom_config['host'] ?? '';
+                $path = $node_custom_config['path'] ?? '/';
+
+                $v2rayn_array = [
+                    'v' => '2',
+                    'ps' => $node_raw->name,
+                    'add' => $server,
+                    'port' => $v2_port,
+                    'id' => $user->uuid,
+                    'aid' => $alter_id,
+                    'net' => $network,
+                    'type' => $header_type,
+                    'host' => $host,
+                    'path' => $path,
+                    'tls' => $security,
+                ];
+
+                $links .= 'vmess://' . base64_encode(json_encode($v2rayn_array)) . PHP_EOL;
             }
         }
 
@@ -238,39 +233,37 @@ final class LinkController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
-            switch ($node_raw->sort) {
-                case '14':
-                    $trojan_port = $node_custom_config['trojan_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
-                    $host = $node_custom_config['host'] ?? '';
-                    $allow_insecure = $node_custom_config['allow_insecure'] ?? '0';
-                    $security = $node_custom_config['security'] ?? \array_key_exists('enable_xtls', $node_custom_config) && $node_custom_config['enable_xtls'] === '1' ? 'xtls' : 'tls';
-                    $mux = $node_custom_config['mux'] ?? '';
-                    $transport = $node_custom_config['transport'] ?? \array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
-
-                    $transport_plugin = $node_custom_config['transport_plugin'] ?? '';
-                    $transport_method = $node_custom_config['transport_method'] ?? '';
-                    $servicename = $node_custom_config['servicename'] ?? '';
-                    $path = $node_custom_config['path'] ?? '';
-
-                    $links .= 'trojan://' . $user->uuid . '@' . $server . ':' . $trojan_port . '?peer=' . $host . '&sni=' . $host .
+            if ($node_raw->sort === '14') {
+                $trojan_port = $node_custom_config['trojan_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
+                $host = $node_custom_config['host'] ?? '';
+                $allow_insecure = $node_custom_config['allow_insecure'] ?? '0';
+                $security = $node_custom_config['security'] ?? array_key_exists('enable_xtls', $node_custom_config) && $node_custom_config['enable_xtls'] === '1' ? 'xtls' : 'tls';
+                $mux = $node_custom_config['mux'] ?? '';
+                $transport = $node_custom_config['transport'] ?? array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
+
+                $transport_plugin = $node_custom_config['transport_plugin'] ?? '';
+                $transport_method = $node_custom_config['transport_method'] ?? '';
+                $servicename = $node_custom_config['servicename'] ?? '';
+                $path = $node_custom_config['path'] ?? '';
+
+                $links .= 'trojan://' . $user->uuid . '@' . $server . ':' . $trojan_port . '?peer=' . $host . '&sni=' . $host .
                     '&obfs=' . $transport_plugin . '&path=' . $path . '&mux=' . $mux . '&allowInsecure=' . $allow_insecure .
                     '&obfsParam=' . $transport_method . '&type=' . $transport . '&security=' . $security . '&serviceName=' . $servicename . '#' .
                     $node_raw->name . PHP_EOL;
-                    break;
             }
         }
 
         return $links;
     }
 
-    public static function getTraditionalSub($user)
+    public static function getTraditionalSub($user): string
     {
         $userid = $user->id;
         $token = Link::where('userid', $userid)->first();

+ 11 - 14
src/Controllers/PasswordController.php

@@ -11,8 +11,11 @@ use App\Services\Captcha;
 use App\Services\Password;
 use App\Utils\Hash;
 use App\Utils\ResponseHelper;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function time;
 
 /*
  * Class Password
@@ -23,9 +26,9 @@ use Slim\Http\ServerRequest;
 final class PasswordController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function reset(ServerRequest $request, Response $response, array $args)
+    public function reset(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $captcha = [];
 
@@ -40,10 +43,7 @@ final class PasswordController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
-    public function handleReset(ServerRequest $request, Response $response, array $args)
+    public function handleReset(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         if (Setting::obtain('enable_reset_password_captcha') === true) {
             $ret = Captcha::verify($request->getParams());
@@ -69,11 +69,11 @@ final class PasswordController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function token(ServerRequest $request, Response $response, array $args)
     {
-        $token = PasswordReset::where('token', $args['token'])->where('expire_time', '>', \time())->orderBy('id', 'desc')->first();
+        $token = PasswordReset::where('token', $args['token'])->where('expire_time', '>', time())->orderBy('id', 'desc')->first();
         if ($token === null) {
             return $response->withStatus(302)->withHeader('Location', '/password/reset');
         }
@@ -83,10 +83,7 @@ final class PasswordController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
-    public function handleToken(ServerRequest $request, Response $response, array $args)
+    public function handleToken(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $tokenStr = $args['token'];
         $password = $request->getParam('password');
@@ -101,7 +98,7 @@ final class PasswordController extends BaseController
         }
 
         /** @var PasswordReset $token */
-        $token = PasswordReset::where('token', $tokenStr)->where('expire_time', '>', \time())->orderBy('id', 'desc')->first();
+        $token = PasswordReset::where('token', $tokenStr)->where('expire_time', '>', time())->orderBy('id', 'desc')->first();
         if ($token === null) {
             return ResponseHelper::error($response, '链接已经失效,请重新获取');
         }
@@ -125,7 +122,7 @@ final class PasswordController extends BaseController
         }
 
         // 禁止链接多次使用
-        $token->expire_time = \time();
+        $token->expire_time = time();
         $token->save();
 
         return ResponseHelper::successfully($response, '重置成功');

+ 31 - 15
src/Controllers/SubController.php

@@ -10,6 +10,10 @@ use App\Models\UserSubscribeLog;
 use App\Utils\Tools;
 use Psr\Http\Message\ResponseInterface;
 use Symfony\Component\Yaml\Yaml;
+use function array_key_exists;
+use function array_merge;
+use function in_array;
+use function json_decode;
 
 /**
  *  SubController
@@ -42,7 +46,7 @@ final class SubController extends BaseController
         }
 
         $subtype_list = ['json', 'clash', 'sip008'];
-        if (! \in_array($subtype, $subtype_list)) {
+        if (! in_array($subtype, $subtype_list)) {
             return $response->withJson([
                 'ret' => 0,
             ]);
@@ -81,9 +85,13 @@ final class SubController extends BaseController
                 $sub_info
             );
         }
+
+        return $response->withJson([
+            'ret' => 0,
+        ]);
     }
 
-    public static function getJson($user)
+    public static function getJson($user): array
     {
         $nodes = [];
         //篩選出用戶能連接的節點
@@ -96,13 +104,15 @@ final class SubController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
+            $node = [];
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
+
             switch ($node_raw->sort) {
                 case '0':
                     $plugin = $node_custom_config['plugin'] ?? '';
@@ -133,7 +143,7 @@ final class SubController extends BaseController
                     $host = $node_custom_config['host'] ?? '';
                     $servicename = $node_custom_config['servicename'] ?? '';
                     $path = $node_custom_config['path'] ?? '/';
-                    $tls = \in_array($security, ['tls', 'xtls']) ? '1' : '0';
+                    $tls = in_array($security, ['tls', 'xtls']) ? '1' : '0';
                     $enable_vless = $node_custom_config['enable_vless'] ?? '0';
                     $node = [
                         'name' => $node_raw->name,
@@ -161,9 +171,9 @@ final class SubController extends BaseController
                     $trojan_port = $node_custom_config['trojan_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
                     $host = $node_custom_config['host'] ?? '';
                     $allow_insecure = $node_custom_config['allow_insecure'] ?? '0';
-                    $security = $node_custom_config['security'] ?? \array_key_exists('enable_xtls', $node_custom_config) && $node_custom_config['enable_xtls'] === '1' ? 'xtls' : 'tls';
+                    $security = $node_custom_config['security'] ?? array_key_exists('enable_xtls', $node_custom_config) && $node_custom_config['enable_xtls'] === '1' ? 'xtls' : 'tls';
                     $mux = $node_custom_config['mux'] ?? '';
-                    $transport = $node_custom_config['transport'] ?? \array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
+                    $transport = $node_custom_config['transport'] ?? array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
 
                     $transport_plugin = $node_custom_config['transport_plugin'] ?? '';
                     $transport_method = $node_custom_config['transport_method'] ?? '';
@@ -189,9 +199,11 @@ final class SubController extends BaseController
                     ];
                     break;
             }
-            if ($node === null) {
+
+            if ($node === []) {
                 continue;
             }
+
             $nodes[] = $node;
         }
 
@@ -223,13 +235,15 @@ final class SubController extends BaseController
             ->get();
 
         foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
+            $node_custom_config = json_decode($node_raw->custom_config, true);
+            $node = [];
             //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
+            if (! array_key_exists('server_user', $node_custom_config)) {
                 $server = $node_raw->server;
             } else {
                 $server = $node_custom_config['server_user'];
             }
+
             switch ($node_raw->sort) {
                 case '0':
                     $plugin = $node_custom_config['plugin'] ?? '';
@@ -258,7 +272,7 @@ final class SubController extends BaseController
                     $network = $node_custom_config['network'] ?? '';
                     $host = $node_custom_config['host'] ?? '';
                     $allow_insecure = $node_custom_config['allow_insecure'] ?? false;
-                    $tls = \in_array($security, ['tls', 'xtls']) ? true : false;
+                    $tls = in_array($security, ['tls', 'xtls']);
                     // Clash 特定配置
                     $udp = $node_custom_config['udp'] ?? true;
                     $ws_opts = $node_custom_config['ws-opts'] ?? $node_custom_config['ws_opts'] ?? null;
@@ -288,7 +302,7 @@ final class SubController extends BaseController
                     break;
                 case '14':
                     $trojan_port = $node_custom_config['trojan_port'] ?? ($node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443));
-                    $network = $node_custom_config['network'] ?? \array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
+                    $network = $node_custom_config['network'] ?? array_key_exists('grpc', $node_custom_config) && $node_custom_config['grpc'] === '1' ? 'grpc' : 'tcp';
                     $host = $node_custom_config['host'] ?? '';
                     $allow_insecure = $node_custom_config['allow_insecure'] ?? false;
                     // Clash 特定配置
@@ -312,9 +326,11 @@ final class SubController extends BaseController
 
                     break;
             }
-            if ($node === null) {
+
+            if ($node === []) {
                 continue;
             }
+
             $nodes[] = $node;
 
             $indexes = [0, 1, 2, 5, 7, 8, 9, 12];
@@ -333,7 +349,7 @@ final class SubController extends BaseController
             'proxies' => $nodes,
         ];
 
-        return Yaml::dump(\array_merge($clash, $clash_config), 3, 1);
+        return Yaml::dump(array_merge($clash, $clash_config), 3, 1);
     }
 
     // SIP008 SS 订阅
@@ -341,7 +357,7 @@ final class SubController extends BaseController
     {
     }
 
-    public static function getUniversalSub($user)
+    public static function getUniversalSub($user): string
     {
         $userid = $user->id;
         $token = Link::where('userid', $userid)->first();

+ 7 - 7
src/Controllers/User/CouponController.php

@@ -8,16 +8,16 @@ use App\Controllers\BaseController;
 use App\Models\Order;
 use App\Models\Product;
 use App\Models\UserCoupon;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function json_decode;
+use function time;
 
 final class CouponController extends BaseController
 {
-    /**
-     * @param array     $args
-     */
-    public function check(ServerRequest $request, Response $response, array $args)
+    public function check(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $coupon_raw = $antiXss->xss_clean($request->getParam('coupon'));
@@ -39,7 +39,7 @@ final class CouponController extends BaseController
             ]);
         }
 
-        if ($coupon->expire_time < \time()) {
+        if ($coupon->expire_time < time()) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '优惠码无效',
@@ -55,7 +55,7 @@ final class CouponController extends BaseController
             ]);
         }
 
-        $limit = \json_decode($coupon->limit);
+        $limit = json_decode($coupon->limit);
 
         if ((int) $limit->disabled === 1) {
             return $response->withJson([
@@ -87,7 +87,7 @@ final class CouponController extends BaseController
             }
         }
 
-        $content = \json_decode($coupon->content);
+        $content = json_decode($coupon->content);
 
         if ($content->type === 'percentage') {
             $discount = $product->price * $content->value / 100;

+ 4 - 2
src/Controllers/User/DetectController.php

@@ -6,15 +6,17 @@ namespace App\Controllers\User;
 
 use App\Controllers\BaseController;
 use App\Models\DetectRule;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
 final class DetectController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $rules = DetectRule::get();
 

+ 17 - 7
src/Controllers/User/InvoiceController.php

@@ -9,9 +9,13 @@ use App\Models\Invoice;
 use App\Models\Paylist;
 use App\Services\Payment;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function json_decode;
+use function time;
 
 final class InvoiceController extends BaseController
 {
@@ -28,7 +32,10 @@ final class InvoiceController extends BaseController
         ],
     ];
 
-    public function invoice(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function invoice(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -37,7 +44,10 @@ final class InvoiceController extends BaseController
         );
     }
 
-    public function detail(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function detail(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $id = $antiXss->xss_clean($args['id']);
@@ -58,7 +68,7 @@ final class InvoiceController extends BaseController
         $invoice->create_time = Tools::toDateTime($invoice->create_time);
         $invoice->update_time = Tools::toDateTime($invoice->update_time);
         $invoice->pay_time = Tools::toDateTime($invoice->pay_time);
-        $invoice_content = \json_decode($invoice->content);
+        $invoice_content = json_decode($invoice->content);
 
         return $response->write(
             $this->view()
@@ -70,7 +80,7 @@ final class InvoiceController extends BaseController
         );
     }
 
-    public function payBalance(ServerRequest $request, Response $response, array $args)
+    public function payBalance(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $invoice_id = $antiXss->xss_clean($request->getParam('invoice_id'));
@@ -97,8 +107,8 @@ final class InvoiceController extends BaseController
         $user->save();
 
         $invoice->status = 'paid_balance';
-        $invoice->update_time = \time();
-        $invoice->pay_time = \time();
+        $invoice->update_time = time();
+        $invoice->pay_time = time();
         $invoice->save();
 
         return $response->withJson([
@@ -107,7 +117,7 @@ final class InvoiceController extends BaseController
         ]);
     }
 
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $invoices = Invoice::orderBy('id', 'desc')->get();
 

+ 6 - 4
src/Controllers/User/LogController.php

@@ -8,6 +8,8 @@ use App\Controllers\BaseController;
 use App\Models\DetectLog;
 use App\Models\UserSubscribeLog;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
@@ -16,9 +18,9 @@ final class LogController extends BaseController
     /**
      * 订阅记录
      *
-     * @param array    $args
+     * @throws Exception
      */
-    public function subscribe(ServerRequest $request, Response $response, array $args)
+    public function subscribe(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $logs = UserSubscribeLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
 
@@ -29,9 +31,9 @@ final class LogController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function detect(ServerRequest $request, Response $response, array $args)
+    public function detect(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $logs = DetectLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
 

+ 24 - 13
src/Controllers/User/MFAController.php

@@ -5,6 +5,8 @@ declare(strict_types=1);
 namespace App\Controllers\User;
 
 use App\Controllers\BaseController;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use Vectorface\GoogleAuthenticator;
@@ -14,45 +16,45 @@ use Vectorface\GoogleAuthenticator;
  */
 final class MFAController extends BaseController
 {
-    /**
-     * @param array     $args
-     */
-    public function checkGa(ServerRequest $request, Response $response, array $args)
+    public function checkGa(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $code = $request->getParam('code');
+
         if ($code === '') {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '二维码不能为空',
             ]);
         }
+
         $user = $this->user;
         $ga = new GoogleAuthenticator();
         $rcode = $ga->verifyCode($user->ga_token, $code);
+
         if (! $rcode) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '测试错误',
             ]);
         }
+
         return $response->withJson([
             'ret' => 1,
             'msg' => '测试成功',
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function setGa(ServerRequest $request, Response $response, array $args)
+    public function setGa(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $enable = $request->getParam('enable');
+
         if ($enable === '') {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '选项无效',
             ]);
         }
+
         $user = $this->user;
         $user->ga_enable = $enable;
         $user->save();
@@ -62,21 +64,30 @@ final class MFAController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetGa(ServerRequest $request, Response $response, array $args)
+    public function resetGa(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $ga = new GoogleAuthenticator();
-        $secret = $ga->createSecret();
+        $secret = '';
+
+        try {
+            $secret = $ga->createSecret();
+        } catch (Exception $e) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '重置失败',
+            ]);
+        }
+
         $user = $this->user;
         $user->ga_token = $secret;
+
         if ($user->save()) {
             return $response->withJson([
                 'ret' => 1,
                 'msg' => '重置成功',
             ]);
         }
+
         return $response->withJson([
             'ret' => 0,
             'msg' => '重置失败',

+ 31 - 17
src/Controllers/User/OrderController.php

@@ -10,9 +10,14 @@ use App\Models\Order;
 use App\Models\Product;
 use App\Models\UserCoupon;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function json_decode;
+use function json_encode;
+use function time;
 
 final class OrderController extends BaseController
 {
@@ -31,7 +36,10 @@ final class OrderController extends BaseController
         ],
     ];
 
-    public function order(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function order(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -40,7 +48,10 @@ final class OrderController extends BaseController
         );
     }
 
-    public function create(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function create(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $product_id = $antiXss->xss_clean($request->getQueryParams()['product_id']) ?? null;
@@ -51,7 +62,7 @@ final class OrderController extends BaseController
 
         $product = Product::where('id', $product_id)->first();
 
-        $product->content = \json_decode($product->content);
+        $product->content = json_decode($product->content);
 
         return $response->write(
             $this->view()
@@ -60,7 +71,10 @@ final class OrderController extends BaseController
         );
     }
 
-    public function detail(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function detail(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $id = $antiXss->xss_clean($args['id']);
@@ -76,14 +90,14 @@ final class OrderController extends BaseController
         $order->create_time = Tools::toDateTime($order->create_time);
         $order->update_time = Tools::toDateTime($order->update_time);
 
-        $product_content = \json_decode($order->product_content);
+        $product_content = json_decode($order->product_content);
 
         $invoice = Invoice::where('order_id', $id)->first();
         $invoice->status = Tools::getInvoiceStatus($invoice);
         $invoice->create_time = Tools::toDateTime($invoice->create_time);
         $invoice->update_time = Tools::toDateTime($invoice->update_time);
         $invoice->pay_time = Tools::toDateTime($invoice->pay_time);
-        $invoice_content = \json_decode($invoice->content);
+        $invoice_content = json_decode($invoice->content);
 
         return $response->write(
             $this->view()
@@ -95,7 +109,7 @@ final class OrderController extends BaseController
         );
     }
 
-    public function process(ServerRequest $request, Response $response, array $args)
+    public function process(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $coupon_raw = $antiXss->xss_clean($request->getParam('coupon'));
@@ -130,14 +144,14 @@ final class OrderController extends BaseController
                 ]);
             }
 
-            if ($coupon->expire_time < \time()) {
+            if ($coupon->expire_time < time()) {
                 return $response->withJson([
                     'ret' => 0,
                     'msg' => '优惠码无效',
                 ]);
             }
 
-            $coupon_limit = \json_decode($coupon->limit);
+            $coupon_limit = json_decode($coupon->limit);
 
             if ((int) $coupon_limit->disabled === 1) {
                 return $response->withJson([
@@ -168,7 +182,7 @@ final class OrderController extends BaseController
                 }
             }
 
-            $content = \json_decode($coupon->content);
+            $content = json_decode($coupon->content);
 
             if ($content->type === 'percentage') {
                 $discount = $product->price * $content->value / 100;
@@ -179,7 +193,7 @@ final class OrderController extends BaseController
             $buy_price = $product->price - $discount;
         }
 
-        $product_limit = \json_decode($product->limit);
+        $product_limit = json_decode($product->limit);
 
         if ($product_limit->class_required !== '') {
             if ($user->class < $product_limit->class_required) {
@@ -218,8 +232,8 @@ final class OrderController extends BaseController
         $order->coupon = $coupon_raw;
         $order->price = $buy_price;
         $order->status = 'pending_payment';
-        $order->create_time = \time();
-        $order->update_time = \time();
+        $order->create_time = time();
+        $order->update_time = time();
         $order->save();
 
         $invoice_content = [];
@@ -241,11 +255,11 @@ final class OrderController extends BaseController
         $invoice = new Invoice();
         $invoice->user_id = $user->id;
         $invoice->order_id = $order->id;
-        $invoice->content = \json_encode($invoice_content);
+        $invoice->content = json_encode($invoice_content);
         $invoice->price = $buy_price;
         $invoice->status = 'unpaid';
-        $invoice->create_time = \time();
-        $invoice->update_time = \time();
+        $invoice->create_time = time();
+        $invoice->update_time = time();
         $invoice->pay_time = 0;
         $invoice->save();
 
@@ -262,7 +276,7 @@ final class OrderController extends BaseController
         ]);
     }
 
-    public function ajax(ServerRequest $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $orders = Order::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
 

+ 8 - 2
src/Controllers/User/ProductController.php

@@ -6,12 +6,18 @@ namespace App\Controllers\User;
 
 use App\Controllers\BaseController;
 use App\Models\Product;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function json_decode;
 
 final class ProductController extends BaseController
 {
-    public function product(ServerRequest $request, Response $response, array $args)
+    /**
+     * @throws Exception
+     */
+    public function product(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $products = Product::where('status', '1')
             ->where('type', 'tabp')
@@ -19,7 +25,7 @@ final class ProductController extends BaseController
             ->get();
 
         foreach ($products as $product) {
-            $product->content = \json_decode($product->content);
+            $product->content = json_decode($product->content);
         }
 
         return $response->write(

+ 2 - 1
src/Controllers/User/ServerController.php

@@ -7,6 +7,7 @@ namespace App\Controllers\User;
 use App\Controllers\BaseController;
 use App\Models\Node;
 use App\Utils\Tools;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
@@ -17,7 +18,7 @@ use Slim\Http\ServerRequest;
 final class ServerController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function userServerPage(ServerRequest $request, Response $response, array $args): ResponseInterface
     {

+ 13 - 18
src/Controllers/User/ShopController.php

@@ -11,24 +11,25 @@ use App\Models\Payback;
 use App\Models\Setting;
 use App\Models\Shop;
 use App\Utils\ResponseHelper;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function time;
 
 final class ShopController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function shop(ServerRequest $request, Response $response, array $args)
+    public function shop(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $shops = Shop::where('status', 1)->orderBy('name')->get();
+
         return $response->write($this->view()->assign('shops', $shops)->fetch('user/shop.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function couponCheck(ServerRequest $request, Response $response, array $args)
+    public function couponCheck(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $coupon = $request->getParam('coupon');
         $coupon = trim($coupon);
@@ -77,10 +78,7 @@ final class ShopController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function buy(ServerRequest $request, Response $response, array $args)
+    public function buy(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $shop = $request->getParam('shop');
@@ -117,7 +115,7 @@ final class ShopController extends BaseController
             if ($coupon->order($shop->id) === false) {
                 return ResponseHelper::error($response, '此优惠码不适用于此商品');
             }
-            if ($coupon->expire < \time()) {
+            if ($coupon->expire < time()) {
                 return ResponseHelper::error($response, '此优惠码已过期');
             }
             if ($coupon->onetime > 0) {
@@ -148,11 +146,11 @@ final class ShopController extends BaseController
         $bought = new Bought();
         $bought->userid = $user->id;
         $bought->shopid = $shop->id;
-        $bought->datetime = \time();
+        $bought->datetime = time();
         if ($autorenew === 0 || $shop->auto_renew === 0) {
             $bought->renew = 0;
         } else {
-            $bought->renew = \time() + $shop->auto_renew * 86400;
+            $bought->renew = time() + $shop->auto_renew * 86400;
         }
         $bought->coupon = $coupon_code;
         $bought->price = $price;
@@ -167,10 +165,7 @@ final class ShopController extends BaseController
         return ResponseHelper::successfully($response, '购买成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function buyTrafficPackage(ServerRequest $request, Response $response, array $args)
+    public function buyTrafficPackage(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $user = $this->user;
         $shop = $request->getParam('shop');
@@ -200,7 +195,7 @@ final class ShopController extends BaseController
         $bought = new Bought();
         $bought->userid = $user->id;
         $bought->shopid = $shop->id;
-        $bought->datetime = \time();
+        $bought->datetime = time();
         $bought->renew = 0;
         $bought->coupon = 0;
         $bought->price = $price;

+ 15 - 15
src/Controllers/User/TicketController.php

@@ -8,10 +8,15 @@ use App\Controllers\BaseController;
 use App\Models\Ticket;
 use App\Models\User;
 use App\Utils\Tools;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function array_merge;
+use function json_decode;
+use function json_encode;
+use function time;
 
 /**
  *  TicketController
@@ -19,7 +24,7 @@ use voku\helper\AntiXSS;
 final class TicketController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function ticket(ServerRequest $request, Response $response, array $args): ?ResponseInterface
     {
@@ -49,9 +54,6 @@ final class TicketController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
     public function ticketAdd(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $title = $request->getParam('title');
@@ -71,15 +73,15 @@ final class TicketController extends BaseController
                 'comment_id' => 0,
                 'commenter_name' => $this->user->user_name,
                 'comment' => $antiXss->xss_clean($comment),
-                'datetime' => \time(),
+                'datetime' => time(),
             ],
         ];
 
         $ticket = new Ticket();
         $ticket->title = $antiXss->xss_clean($title);
-        $ticket->content = \json_encode($content);
+        $ticket->content = json_encode($content);
         $ticket->userid = $this->user->id;
-        $ticket->datetime = \time();
+        $ticket->datetime = time();
         $ticket->status = 'open_wait_admin';
         $ticket->type = $antiXss->xss_clean($type);
         $ticket->save();
@@ -120,9 +122,6 @@ final class TicketController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function ticketUpdate(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
@@ -143,17 +142,17 @@ final class TicketController extends BaseController
 
         $antiXss = new AntiXSS();
 
-        $content_old = \json_decode($ticket->content, true);
+        $content_old = json_decode($ticket->content, true);
         $content_new = [
             [
                 'comment_id' => $content_old[count($content_old) - 1]['comment_id'] + 1,
                 'commenter_name' => $this->user->user_name,
                 'comment' => $antiXss->xss_clean($comment),
-                'datetime' => \time(),
+                'datetime' => time(),
             ],
         ];
 
-        $ticket->content = \json_encode(\array_merge($content_old, $content_new));
+        $ticket->content = json_encode(array_merge($content_old, $content_new));
         $ticket->status = 'open_wait_admin';
         $ticket->save();
 
@@ -194,13 +193,13 @@ final class TicketController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
     public function ticketView(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->where('userid', $this->user->id)->first();
-        $comments = \json_decode($ticket->content, true);
+        $comments = json_decode($ticket->content, true);
 
         $ticket->status = Tools::getTicketStatus($ticket);
         $ticket->type = Tools::getTicketType($ticket);
@@ -221,6 +220,7 @@ final class TicketController extends BaseController
                 'ticket' => $ticket,
             ]);
         }
+
         return $response->write(
             $this->view()
                 ->assign('ticket', $ticket)

+ 69 - 124
src/Controllers/UserController.php

@@ -22,16 +22,20 @@ use App\Services\Config;
 use App\Services\DB;
 use App\Services\MFA;
 use App\Services\Payment;
-use App\Utils\Check;
 use App\Utils\Cookie;
 use App\Utils\Hash;
 use App\Utils\ResponseHelper;
 use App\Utils\TelegramSessionManager;
 use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
 use Ramsey\Uuid\Uuid;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use voku\helper\AntiXSS;
+use function in_array;
+use function json_decode;
+use function time;
 
 /**
  *  HomeController
@@ -39,9 +43,9 @@ use voku\helper\AntiXSS;
 final class UserController extends BaseController
 {
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function index(ServerRequest $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $captcha = [];
 
@@ -67,9 +71,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function code(ServerRequest $request, Response $response, array $args)
+    public function code(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $codes = Code::where('type', '<>', '-2')
@@ -88,17 +92,14 @@ final class UserController extends BaseController
         );
     }
 
-    /**
-     * @param array     $args
-     */
-    public function codeCheck(ServerRequest $request, Response $response, array $args)
+    public function codeCheck(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $time = $request->getQueryParams()['time'];
         $codes = Code::where('userid', '=', $this->user->id)
             ->where('usedatetime', '>', date('Y-m-d H:i:s', $time))
             ->first();
 
-        if ($codes !== null && strpos($codes->code, '充值') !== false) {
+        if ($codes !== null && str_contains($codes->code, '充值')) {
             return $response->withJson([
                 'ret' => 1,
             ]);
@@ -108,10 +109,7 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function codePost(ServerRequest $request, Response $response, array $args)
+    public function codePost(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $code = trim($request->getParam('code'));
         if ($code === '') {
@@ -150,8 +148,8 @@ final class UserController extends BaseController
         }
 
         if ($codeq->type === 10002) {
-            if (\time() > strtotime($user->expire_in)) {
-                $user->expire_in = date('Y-m-d H:i:s', \time() + (int) $codeq->number * 86400);
+            if (time() > strtotime($user->expire_in)) {
+                $user->expire_in = date('Y-m-d H:i:s', time() + (int) $codeq->number * 86400);
             } else {
                 $user->expire_in = date('Y-m-d H:i:s', strtotime($user->expire_in) + (int) $codeq->number * 86400);
             }
@@ -160,7 +158,7 @@ final class UserController extends BaseController
 
         if ($codeq->type >= 1 && $codeq->type <= 10000) {
             if ($user->class === 0 || $user->class !== $codeq->type) {
-                $user->class_expire = date('Y-m-d H:i:s', \time());
+                $user->class_expire = date('Y-m-d H:i:s', time());
                 $user->save();
             }
             $user->class_expire = date('Y-m-d H:i:s', strtotime($user->class_expire) + (int) $codeq->number * 86400);
@@ -174,10 +172,7 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetPort(ServerRequest $request, Response $response, array $args)
+    public function resetPort(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $temp = $this->user->resetPort();
         return $response->withJson([
@@ -186,10 +181,7 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function specifyPort(ServerRequest $request, Response $response, array $args)
+    public function specifyPort(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $temp = $this->user->specifyPort((int) $request->getParam('port'));
         return $response->withJson([
@@ -199,9 +191,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function profile(ServerRequest $request, Response $response, array $args)
+    public function profile(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         // 登录IP
         $loginips = LoginIp::where('userid', '=', $this->user->id)->where('type', '=', 0)->orderBy('datetime', 'desc')->take(10)->get();
@@ -215,9 +207,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function announcement(ServerRequest $request, Response $response, array $args)
+    public function announcement(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $Anns = Ann::orderBy('date', 'desc')->get();
 
@@ -236,9 +228,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function docs(ServerRequest $request, Response $response, array $args)
+    public function docs(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $docs = Docs::orderBy('id', 'desc')->get();
 
@@ -257,9 +249,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function media(ServerRequest $request, Response $response, array $args)
+    public function media(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $results = [];
         $pdo = DB::getPdo();
@@ -270,13 +262,14 @@ final class UserController extends BaseController
 
             $unlock = StreamMedia::where('node_id', $node_id)
                 ->orderBy('id', 'desc')
-                ->where('created_at', '>', \time() - 86460) // 只获取最近一天零一分钟内上报的数据
+                ->where('created_at', '>', time() - 86460) // 只获取最近一天零一分钟内上报的数据
                 ->first();
 
             if ($unlock !== null && $node !== null) {
-                $details = \json_decode($unlock->result, true);
+                $details = json_decode($unlock->result, true);
                 $details = str_replace('Originals Only', '仅限自制', $details);
                 $details = str_replace('Oversea Only', '仅限海外', $details);
+                $info = [];
 
                 foreach ($details as $key => $value) {
                     $info = [
@@ -286,7 +279,7 @@ final class UserController extends BaseController
                     ];
                 }
 
-                array_push($results, $info);
+                $results[] = $info;
             }
         }
 
@@ -295,11 +288,11 @@ final class UserController extends BaseController
                 $key_node = Node::where('id', $key)->first();
                 $value_node = StreamMedia::where('node_id', $value)
                     ->orderBy('id', 'desc')
-                    ->where('created_at', '>', \time() - 86460) // 只获取最近一天零一分钟内上报的数据
+                    ->where('created_at', '>', time() - 86460) // 只获取最近一天零一分钟内上报的数据
                     ->first();
 
                 if ($value_node !== null) {
-                    $details = \json_decode($value_node->result, true);
+                    $details = json_decode($value_node->result, true);
                     $details = str_replace('Originals Only', '仅限自制', $details);
                     $details = str_replace('Oversea Only', '仅限海外', $details);
 
@@ -309,7 +302,7 @@ final class UserController extends BaseController
                         'unlock_item' => $details,
                     ];
 
-                    array_push($results, $info);
+                    $results[] = $info;
                 }
             }
         }
@@ -323,9 +316,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function edit(ServerRequest $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $themes = Tools::getDir(BASE_PATH . '/resources/views');
         $bind_token = TelegramSessionManager::addBindSession($this->user);
@@ -344,9 +337,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function invite(ServerRequest $request, Response $response, array $args)
+    public function invite(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $code = InviteCode::where('user_id', $this->user->id)->first();
         if ($code === null) {
@@ -377,10 +370,7 @@ final class UserController extends BaseController
             ->fetch('user/invite.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updatePassword(ServerRequest $request, Response $response, array $args)
+    public function updatePassword(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $oldpwd = $request->getParam('oldpwd');
         $pwd = $request->getParam('pwd');
@@ -407,10 +397,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '修改成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateEmail(ServerRequest $request, Response $response, array $args)
+    public function updateEmail(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
 
@@ -425,7 +412,7 @@ final class UserController extends BaseController
 
         if (Setting::obtain('reg_email_verify')) {
             $emailcode = $request->getParam('emailcode');
-            $mailcount = EmailVerify::where('email', '=', $newemail)->where('code', '=', $emailcode)->where('expire_in', '>', \time())->first();
+            $mailcount = EmailVerify::where('email', '=', $newemail)->where('code', '=', $emailcode)->where('expire_in', '>', time())->first();
             if ($mailcount === null) {
                 return ResponseHelper::error($response, '您的邮箱验证码不正确');
             }
@@ -435,7 +422,7 @@ final class UserController extends BaseController
             return ResponseHelper::error($response, '未填写邮箱');
         }
 
-        $check_res = Check::isEmailLegal($newemail);
+        $check_res = Tools::isEmailLegal($newemail);
         if ($check_res['ret'] === 0) {
             return $response->withJson($check_res);
         }
@@ -454,10 +441,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '修改成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateUsername(ServerRequest $request, Response $response, array $args)
+    public function updateUsername(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $antiXss = new AntiXSS();
 
@@ -471,9 +455,9 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function bought(ServerRequest $request, Response $response, array $args)
+    public function bought(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $shops = Bought::where('userid', $this->user->id)->orderBy('id', 'desc')->paginate(15, ['*'], 'page', $pageNum);
@@ -489,16 +473,14 @@ final class UserController extends BaseController
             ]);
         }
         $render = Tools::paginateRender($shops);
+
         return $response->write($this->view()
             ->assign('shops', $shops)
             ->assign('render', $render)
             ->fetch('user/bought.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function deleteBoughtGet(ServerRequest $request, Response $response, array $args)
+    public function deleteBoughtGet(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $request->getParam('id');
         $shop = Bought::where('id', $id)->where('userid', $this->user->id)->first();
@@ -517,10 +499,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '关闭自动续费成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateContact(ServerRequest $request, Response $response, array $args)
+    public function updateContact(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
 
@@ -561,10 +540,7 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateTheme(ServerRequest $request, Response $response, array $args)
+    public function updateTheme(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $antiXss = new AntiXSS();
         $theme = $antiXss->xss_clean($request->getParam('theme'));
@@ -587,13 +563,10 @@ final class UserController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateMail(ServerRequest $request, Response $response, array $args)
+    public function updateMail(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $value = (int) $request->getParam('mail');
-        if (\in_array($value, [0, 1, 2])) {
+        if (in_array($value, [0, 1, 2])) {
             $user = $this->user;
             if ($value === 2 && $_ENV['enable_telegram'] === false) {
                 return ResponseHelper::error(
@@ -608,14 +581,11 @@ final class UserController extends BaseController
         return ResponseHelper::error($response, '非法输入');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetPasswd(ServerRequest $request, Response $response, array $args)
+    public function resetPasswd(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $pwd = Tools::genRandomChar(16);
-        $current_timestamp = \time();
+        $current_timestamp = time();
         $new_uuid = Uuid::uuid3(Uuid::NAMESPACE_DNS, $user->email . '|' . $current_timestamp);
         $existing_uuid = User::where('uuid', $new_uuid)->first();
 
@@ -630,10 +600,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '修改成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function updateMethod(ServerRequest $request, Response $response, array $args)
+    public function updateMethod(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $antiXss = new AntiXSS();
 
@@ -654,19 +621,13 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '修改成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function logout(ServerRequest $request, Response $response, array $args)
+    public function logout(ServerRequest $request, Response $response, array $args): Response
     {
         Auth::logout();
         return $response->withStatus(302)->withHeader('Location', '/');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function doCheckIn(ServerRequest $request, Response $response, array $args)
+    public function doCheckIn(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         if ($_ENV['enable_checkin'] === false) {
             return ResponseHelper::error($response, '暂时还不能签到');
@@ -679,12 +640,13 @@ final class UserController extends BaseController
             }
         }
 
-        if (strtotime($this->user->expire_in) < \time()) {
+        if (strtotime($this->user->expire_in) < time()) {
             return ResponseHelper::error($response, '没有过期的账户才可以签到');
         }
 
         $checkin = $this->user->checkin();
-        if ($checkin['ok'] === false) {
+
+        if (! $checkin['ok']) {
             return ResponseHelper::error($response, $checkin['msg']);
         }
 
@@ -702,17 +664,14 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function kill(ServerRequest $request, Response $response, array $args)
+    public function kill(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write($this->view()->fetch('user/kill.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function handleKill(ServerRequest $request, Response $response, array $args)
+    public function handleKill(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
 
@@ -731,20 +690,18 @@ final class UserController extends BaseController
     }
 
     /**
-     * @param array     $args
+     * @throws Exception
      */
-    public function banned(ServerRequest $request, Response $response, array $args)
+    public function banned(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $user = $this->user;
+
         return $response->write($this->view()
             ->assign('banned_reason', $user->banned_reason)
             ->fetch('user/banned.tpl'));
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetTelegram(ServerRequest $request, Response $response, array $args)
+    public function resetTelegram(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $user->telegramReset();
@@ -752,10 +709,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '重置成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetURL(ServerRequest $request, Response $response, array $args)
+    public function resetURL(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $user->cleanLink();
@@ -763,10 +717,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '重置成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function resetInviteURL(ServerRequest $request, Response $response, array $args)
+    public function resetInviteURL(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $user->clearInviteCodes();
@@ -774,10 +725,7 @@ final class UserController extends BaseController
         return ResponseHelper::successfully($response, '重置成功');
     }
 
-    /**
-     * @param array     $args
-     */
-    public function backtoadmin(ServerRequest $request, Response $response, array $args)
+    public function backtoadmin(ServerRequest $request, Response $response, array $args): Response
     {
         $userid = Cookie::get('uid');
         $adminid = Cookie::get('old_uid');
@@ -797,7 +745,7 @@ final class UserController extends BaseController
                 'old_ip' => null,
                 'old_expire_in' => null,
                 'old_local' => null,
-            ], \time() - 1000);
+            ], time() - 1000);
         }
         $expire_in = Cookie::get('old_expire_in');
         $local = Cookie::get('old_local');
@@ -817,10 +765,7 @@ final class UserController extends BaseController
         return $response->withStatus(302)->withHeader('Location', $local);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function switchThemeMode(ServerRequest $request, Response $response, array $args)
+    public function switchThemeMode(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $user = $this->user;
         if ($user->is_dark_mode === 1) {

+ 8 - 25
src/Controllers/WebAPI/FuncController.php

@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace App\Controllers\Node;
+namespace App\Controllers\WebAPI;
 
 use App\Controllers\BaseController;
 use App\Models\DetectRule;
@@ -13,21 +13,14 @@ use Slim\Http\ServerRequest;
 
 final class FuncController extends BaseController
 {
-    /**
-     * @param array     $args
-     */
-    public function ping(ServerRequest $request, Response $response, array $args)
+    public function ping(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $res = [
+        return $response->withJson([
             'ret' => 1,
-            'data' => 'pong',
-        ];
-        return $response->withJson($res);
+            'data' => 'Pong? Pong!',
+        ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function getDetectLogs(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $rules = DetectRule::all();
@@ -39,9 +32,6 @@ final class FuncController extends BaseController
     }
 
     // Dummy function
-    /**
-     * @param array     $args
-     */
     public function getBlockip(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return ResponseHelper::etagJson($request, $response, [
@@ -50,9 +40,6 @@ final class FuncController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function getUnblockip(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return ResponseHelper::etagJson($request, $response, [
@@ -61,15 +48,11 @@ final class FuncController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function addBlockIp(ServerRequest $request, Response $response, array $args)
+    public function addBlockIp(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $res = [
+        return $response->withJson([
             'ret' => 1,
             'data' => 'ok',
-        ];
-        return $response->withJson($res);
+        ]);
     }
 }

+ 20 - 36
src/Controllers/WebAPI/NodeController.php

@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace App\Controllers\Node;
+namespace App\Controllers\WebAPI;
 
 use App\Controllers\BaseController;
 use App\Models\Node;
@@ -11,40 +11,37 @@ use App\Utils\ResponseHelper;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function json_decode;
+use function json_encode;
+use function time;
 
 final class NodeController extends BaseController
 {
-    /**
-     * @param array     $args
-     */
-    public function saveReport(ServerRequest $request, Response $response, array $args): void
+    public function saveReport(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node_id = $request->getParam('node_id');
         $content = $request->getParam('content');
-        $result = \json_decode(base64_decode($content), true);
+        $result = json_decode(base64_decode($content), true);
         $report = new StreamMedia();
         $report->node_id = $node_id;
-        $report->result = \json_encode($result);
-        $report->created_at = \time();
+        $report->result = json_encode($result);
+        $report->created_at = time();
         $report->save();
-        die('ok');
+
+        return $response->withJson([
+            'ret' => 1,
+            'data' => 'ok',
+        ]);
     }
 
-    /**
-     * @param array     $args
-     */
-    public function info(ServerRequest $request, Response $response, array $args)
+    public function info(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $res = [
+        return $response->withJson([
             'ret' => 1,
             'data' => 'ok',
-        ];
-        return $response->withJson($res);
+        ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function getInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node_id = $args['id'];
@@ -55,7 +52,7 @@ final class NodeController extends BaseController
             ];
             return $response->withJson($res);
         }
-        if (\in_array($node->sort, [0])) {
+        if ($node->sort === 0) {
             $node_explode = explode(';', $node->server);
             $node_server = $node_explode[0];
         } else {
@@ -69,7 +66,7 @@ final class NodeController extends BaseController
             'mu_only' => $node->mu_only,
             'sort' => $node->sort,
             'server' => $node_server,
-            'custom_config' => \json_decode($node->custom_config, true, JSON_UNESCAPED_SLASHES),
+            'custom_config' => json_decode($node->custom_config, true, JSON_UNESCAPED_SLASHES),
             'type' => 'SSPanel-UIM',
             'version' => VERSION,
         ];
@@ -80,24 +77,11 @@ final class NodeController extends BaseController
         ]);
     }
 
-    /**
-     * @param array     $args
-     */
     public function getAllInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $nodes = Node::where('node_ip', '<>', null)->where(
-            static function ($query): void {
-                $query->where('sort', '=', 0)
-                    ->orWhere('sort', '=', 10)
-                    ->orWhere('sort', '=', 12)
-                    ->orWhere('sort', '=', 13)
-                    ->orWhere('sort', '=', 14);
-            }
-        )->get();
-
-        return ResponseHelper::etagJson($request, $response, [
+        return $response->withJson([
             'ret' => 1,
-            'data' => $nodes,
+            'data' => [],
         ]);
     }
 }

+ 14 - 10
src/Controllers/WebAPI/UserController.php

@@ -16,6 +16,10 @@ use Illuminate\Database\Eloquent\Builder;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use function in_array;
+use function is_array;
+use function json_decode;
+use function time;
 
 final class UserController extends BaseController
 {
@@ -38,7 +42,7 @@ final class UserController extends BaseController
             ]);
         }
 
-        $node->update(['node_heartbeat' => \time()]);
+        $node->update(['node_heartbeat' => time()]);
 
         if (($node->node_bandwidth_limit !== 0) && $node->node_bandwidth_limit < $node->node_bandwidth) {
             return $response->withJson([
@@ -57,7 +61,7 @@ final class UserController extends BaseController
             })
             ->get();
 
-        if (\in_array($node->sort, [11, 14])) {
+        if (in_array($node->sort, [11, 14])) {
             $key_list = [
                 'id', 'node_connector', 'node_speedlimit', 'node_iplimit', 'uuid', 'alive_ip',
             ];
@@ -103,8 +107,8 @@ final class UserController extends BaseController
      */
     public function addTraffic(Request $request, Response $response, array $args): ResponseInterface
     {
-        $data = \json_decode($request->getBody()->__toString());
-        if (! $data || ! \is_array($data?->data)) {
+        $data = json_decode($request->getBody()->__toString());
+        if (! $data || ! is_array($data->data)) {
             return $response->withJson([
                 'ret' => 0,
             ]);
@@ -157,8 +161,8 @@ final class UserController extends BaseController
      */
     public function addAliveIp(Request $request, Response $response, array $args): ResponseInterface
     {
-        $data = \json_decode($request->getBody()->__toString());
-        if (! $data || ! \is_array($data?->data)) {
+        $data = json_decode($request->getBody()->__toString());
+        if (! $data || ! is_array($data->data)) {
             return $response->withJson([
                 'ret' => 0,
             ]);
@@ -181,7 +185,7 @@ final class UserController extends BaseController
                 'userid' => $userid,
                 'nodeid' => $node_id,
                 'ip' => $ip,
-                'datetime' => \time(),
+                'datetime' => time(),
             ]);
         }
 
@@ -202,8 +206,8 @@ final class UserController extends BaseController
      */
     public function addDetectLog(Request $request, Response $response, array $args): ResponseInterface
     {
-        $data = \json_decode($request->getBody()->__toString());
-        if (! $data || ! \is_array($data?->data)) {
+        $data = json_decode($request->getBody()->__toString());
+        if (! $data || ! is_array($data->data)) {
             return $response->withJson([
                 'ret' => 0,
             ]);
@@ -226,7 +230,7 @@ final class UserController extends BaseController
                 'user_id' => $user_id,
                 'list_id' => $list_id,
                 'node_id' => $node_id,
-                'datetime' => \time(),
+                'datetime' => time(),
             ]);
         }
 

+ 8 - 2
src/Middleware/ErrorHandler.php

@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace App\Middleware;
 
 use App\Services\View;
+use Exception;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
@@ -18,19 +19,24 @@ use Throwable;
 
 final class ErrorHandler implements MiddlewareInterface
 {
+    /**
+     * @throws Exception
+     */
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         try {
             $response = $handler->handle($request);
         } catch (HttpNotFoundException | HttpMethodNotAllowedException $e) {
             // 404 or 405 throwed by router
-            $smarty = View::getSmarty();
             $code = $e->getCode();
+            $response_factory = AppFactory::determineResponseFactory();
+            $response = $response_factory->createResponse($code);
+            $smarty = View::getSmarty();
             $response->getBody()->write($smarty->fetch("{$code}.tpl"));
             $response = $response->withStatus($code);
         } catch (Throwable $e) {
             $response_factory = AppFactory::determineResponseFactory();
-            if ($_ENV['debug'] ?? false === true) {
+            if ($_ENV['debug'] === true) {
                 $callable_resolver = new CallableResolver(null);
                 $error_handler = new SlimErrorHandler($callable_resolver, $response_factory);
                 $response = $error_handler($request, $e, true, true, false);

+ 1 - 1
src/Middleware/NodeToken.php

@@ -43,7 +43,7 @@ final class NodeToken implements MiddlewareInterface
         if ($_ENV['checkNodeIp'] === true) {
             $ip = $request->getServerParam('REMOTE_ADDR');
             if ($ip !== '127.0.0.1') {
-                if (! Node::where('node_ip', 'LIKE', "${ip}%")->exists()) {
+                if (! Node::where('node_ip', 'LIKE', "{$ip}%")->exists()) {
                     return AppFactory::determineResponseFactory()->createResponse(401)->withJson([
                         'ret' => 0,
                         'data' => 'Invalid request IP.',

+ 10 - 8
src/Models/Bought.php

@@ -4,6 +4,8 @@ declare(strict_types=1);
 
 namespace App\Models;
 
+use function time;
+
 /**
  * Bought Model
  *
@@ -112,7 +114,7 @@ final class Bought extends Model
      */
     public function usedDays(): int
     {
-        return (int) ((\time() - $this->datetime) / 86400);
+        return (int) ((time() - $this->datetime) / 86400);
     }
 
     /*
@@ -122,7 +124,7 @@ final class Bought extends Model
     {
         $shop = $this->shop();
         if ($shop->useLoop()) {
-            return \time() - $shop->resetExp() * 86400 < $this->datetime;
+            return time() - $shop->resetExp() * 86400 < $this->datetime;
         }
         return false;
     }
@@ -130,14 +132,14 @@ final class Bought extends Model
     /*
      * 下一次流量重置时间
      */
-    public function resetTime($unix = false)
+    public function resetTime($unix = false): float|int|string
     {
         $shop = $this->shop();
         if ($shop->useLoop()) {
             $day = 24 * 60 * 60;
-            $resetIndex = 1 + (int) ((\time() - $this->datetime - $day) / ($shop->reset() * $day));
-            $restTime = $resetIndex * $shop->reset() * $day + $this->datetime;
-            $time = \time() + ($day * 86400);
+            $resetIndex = 1 + (int) ((time() - $this->datetime - $day) / ($shop->reset() * $day));
+            $restTime = $resetIndex * $shop->reset() * $day + (int) $this->datetime;
+            $time = time() + ($day * 86400);
             return ! $unix ? date('Y-m-d', strtotime('+1 day', strtotime(date('Y-m-d', (int) $restTime)))) : $time;
         }
         return ! $unix ? '-' : 0;
@@ -146,11 +148,11 @@ final class Bought extends Model
     /*
      * 过期时间
      */
-    public function expTime($unix = false)
+    public function expTime($unix = false): float|int|string
     {
         $shop = $this->shop();
         if ($shop->useLoop()) {
-            $time = $this->datetime + ($shop->resetExp() * 86400);
+            $time = (int) $this->datetime + ($shop->resetExp() * 86400);
             return ! $unix ? date('Y-m-d H:i:s', (int) $time) : $time;
         }
         return ! $unix ? '-' : 0;

+ 10 - 16
src/Models/Code.php

@@ -48,14 +48,11 @@ final class Code extends Model
      */
     public function type(): string
     {
-        switch ($this->type) {
-            case -1:
-                return '充值金额';
-            case -2:
-                return '财务支出';
-            default:
-                return '已经废弃';
-        }
+        return match ($this->type) {
+            -1 => '充值金额',
+            -2 => '财务支出',
+            default => '已经废弃',
+        };
     }
 
     /**
@@ -63,14 +60,11 @@ final class Code extends Model
      */
     public function number(): string
     {
-        switch ($this->type) {
-            case -1:
-                return '充值 ' . $this->number . ' 元';
-            case -2:
-                return '支出 ' . $this->number . ' 元';
-            default:
-                return '已经废弃';
-        }
+        return match ($this->type) {
+            -1 => '充值 ' . $this->number . ' 元',
+            -2 => '支出 ' . $this->number . ' 元',
+            default => '已经废弃',
+        };
     }
 
     /**

+ 4 - 6
src/Models/Coupon.php

@@ -9,12 +9,12 @@ final class Coupon extends Model
     protected $connection = 'default';
     protected $table = 'coupon';
 
-    public function expire()
+    public function expire(): string
     {
         return date('Y-m-d H:i:s', $this->attributes['expire']);
     }
 
-    public function order($shop)
+    public function order($shop): bool
     {
         if ($this->attributes['shop'] === '') {
             return true;
@@ -22,10 +22,8 @@ final class Coupon extends Model
 
         $shop_array = explode(',', $this->attributes['shop']);
 
-        foreach ($shop_array as $shopid) {
-            if ($shopid === $shop) {
-                return true;
-            }
+        if (in_array($shop, $shop_array, true)) {
+            return true;
         }
 
         return false;

Деякі файли не було показано, через те що забагато файлів було змінено