瀏覽代碼

feat: slim4

Irohaede 2 年之前
父節點
當前提交
151d33b936
共有 45 個文件被更改,包括 1510 次插入831 次删除
  1. 0 11
      app/middleware.php
  2. 200 237
      app/routes.php
  3. 5 4
      composer.json
  4. 14 13
      public/index.php
  5. 11 11
      src/Controllers/Admin/AnnController.php
  6. 4 4
      src/Controllers/Admin/ApiController.php
  7. 7 7
      src/Controllers/Admin/CodeController.php
  8. 4 4
      src/Controllers/Admin/DetectBanLogController.php
  9. 14 14
      src/Controllers/Admin/DetectController.php
  10. 7 7
      src/Controllers/Admin/IpController.php
  11. 12 12
      src/Controllers/Admin/NodeController.php
  12. 2 2
      src/Controllers/Admin/SettingController.php
  13. 15 15
      src/Controllers/Admin/ShopController.php
  14. 4 4
      src/Controllers/Admin/SubscribeLogController.php
  15. 9 9
      src/Controllers/Admin/TicketController.php
  16. 4 4
      src/Controllers/Admin/TrafficLogController.php
  17. 10 10
      src/Controllers/Admin/UserController.php
  18. 14 14
      src/Controllers/AdminController.php
  19. 26 25
      src/Controllers/AuthController.php
  20. 9 9
      src/Controllers/HomeController.php
  21. 740 198
      src/Controllers/LinkController.php
  22. 7 7
      src/Controllers/PasswordController.php
  23. 7 7
      src/Controllers/User/DetectController.php
  24. 3 3
      src/Controllers/User/ServerController.php
  25. 6 6
      src/Controllers/User/ShopController.php
  26. 7 7
      src/Controllers/User/TicketController.php
  27. 198 95
      src/Controllers/UserController.php
  28. 14 12
      src/Controllers/WebAPI/FuncController.php
  29. 22 15
      src/Controllers/WebAPI/NodeController.php
  30. 5 5
      src/Controllers/WebAPI/UserController.php
  31. 12 7
      src/Middleware/Admin.php
  32. 18 7
      src/Middleware/Auth.php
  33. 23 21
      src/Middleware/AuthorizationBearer.php
  34. 48 0
      src/Middleware/ErrorHandler.php
  35. 13 4
      src/Middleware/Guest.php
  36. 7 12
      src/Middleware/NodeToken.php
  37. 1 1
      src/Models/Model.php
  38. 1 1
      src/Services/Gateway/AbstractPayment.php
  39. 1 1
      src/Services/Gateway/AopF2F.php
  40. 1 1
      src/Services/Gateway/Epay.php
  41. 1 1
      src/Services/Gateway/PAYJS.php
  42. 1 1
      src/Services/Gateway/PaymentWall.php
  43. 1 1
      src/Services/Gateway/StripeCard.php
  44. 1 1
      src/Services/Gateway/THeadPay.php
  45. 1 1
      src/Services/Gateway/Vmqpay.php

+ 0 - 11
app/middleware.php

@@ -1,11 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-use Slim\App;
-
-return static function (App $app): void {
-    if ($_ENV['debug'] === true) {
-        $app->add(new Zeuxisoo\Whoops\Provider\Slim\WhoopsMiddleware());
-    }
-};

+ 200 - 237
app/routes.php

@@ -4,11 +4,12 @@ declare(strict_types=1);
 
 use App\Middleware\Admin;
 use App\Middleware\Auth;
+use App\Middleware\AuthorizationBearer;
 use App\Middleware\Guest;
 use App\Middleware\NodeToken;
-use Slim\App as SlimApp;
+use Slim\Routing\RouteCollectorProxy;
 
-return function (SlimApp $app): void {
+return function (Slim\App $app): void {
     // Home
     $app->get('/', App\Controllers\HomeController::class . ':index');
     $app->get('/404', App\Controllers\HomeController::class . ':page404');
@@ -24,296 +25,258 @@ return function (SlimApp $app): void {
     $app->post('/telegram_callback', App\Controllers\HomeController::class . ':telegram');
 
     // User Center
-    $app->group('/user', function (): void {
-        $this->get('', App\Controllers\UserController::class . ':index');
-        $this->get('/', App\Controllers\UserController::class . ':index');
-
-        // 签到
-        $this->post('/checkin', App\Controllers\UserController::class . ':doCheckin');
-
-        // 公告
-        $this->get('/announcement', App\Controllers\UserController::class . ':announcement');
-
-        // 文档
-        $this->get('/docs', App\Controllers\UserController::class . ':docs');
-
-        //流媒体解锁
-        $this->get('/media', App\Controllers\UserController::class . ':media');
-
-        $this->get('/profile', App\Controllers\UserController::class . ':profile');
-        $this->get('/invite', App\Controllers\UserController::class . ':invite');
-
-        // 封禁
-        $this->get('/banned', App\Controllers\UserController::class . ':banned');
-
-        // 节点
-        $this->get('/server', App\Controllers\User\ServerController::class . ':userServerPage');
-
-        // 审计
-        $this->get('/detect', App\Controllers\User\DetectController::class . ':index');
-        $this->get('/detect/log', App\Controllers\User\DetectController::class . ':log');
-
-        $this->get('/shop', App\Controllers\User\ShopController::class . ':shop');
-        $this->post('/coupon_check', App\Controllers\User\ShopController::class . ':couponCheck');
-        $this->post('/buy', App\Controllers\User\ShopController::class . ':buy');
-        $this->post('/buy_traffic_package', App\Controllers\User\ShopController::class . ':buyTrafficPackage');
-
-        // 工单
-        $this->get('/ticket', App\Controllers\User\TicketController::class . ':ticket');
-        $this->get('/ticket/create', App\Controllers\User\TicketController::class . ':ticketCreate');
-        $this->post('/ticket', App\Controllers\User\TicketController::class . ':ticketAdd');
-        $this->get('/ticket/{id}/view', App\Controllers\User\TicketController::class . ':ticketView');
-        $this->put('/ticket/{id}', App\Controllers\User\TicketController::class . ':ticketUpdate');
-
-        $this->post('/buy_invite', App\Controllers\UserController::class . ':buyInvite');
-        $this->post('/custom_invite', App\Controllers\UserController::class . ':customInvite');
-        $this->get('/edit', App\Controllers\UserController::class . ':edit');
-        $this->post('/email', App\Controllers\UserController::class . ':updateEmail');
-        $this->post('/username', App\Controllers\UserController::class . ':updateUsername');
-        $this->post('/password', App\Controllers\UserController::class . ':updatePassword');
-        $this->post('/send', App\Controllers\AuthController::class . ':sendVerify');
-        $this->post('/contact_update', App\Controllers\UserController::class . ':updateContact');
-        $this->post('/theme', App\Controllers\UserController::class . ':updateTheme');
-        $this->post('/mail', App\Controllers\UserController::class . ':updateMail');
-        $this->post('/passwd_reset', App\Controllers\UserController::class . ':resetPasswd');
-        $this->post('/method', App\Controllers\UserController::class . ':updateMethod');
-        $this->get('/kill', App\Controllers\UserController::class . ':kill');
-        $this->post('/kill', App\Controllers\UserController::class . ':handleKill');
-        $this->get('/logout', App\Controllers\UserController::class . ':logout');
-        $this->get('/backtoadmin', App\Controllers\UserController::class . ':backtoadmin');
-        $this->get('/code', App\Controllers\UserController::class . ':code');
-
-        $this->get('/code_check', App\Controllers\UserController::class . ':codeCheck');
-        $this->post('/code', App\Controllers\UserController::class . ':codePost');
-        $this->post('/ga_check', App\Controllers\UserController::class . ':checkGa');
-        $this->post('/ga_set', App\Controllers\UserController::class . ':setGa');
-        $this->get('/ga_reset', App\Controllers\UserController::class . ':resetGa');
-        $this->post('/telegram_reset', App\Controllers\UserController::class . ':resetTelegram');
-        $this->post('/unblock', App\Controllers\UserController::class . ':unblock');
-        $this->get('/bought', App\Controllers\UserController::class . ':bought');
-        $this->delete('/bought', App\Controllers\UserController::class . ':deleteBoughtGet');
-        $this->post('/url_reset', App\Controllers\UserController::class . ':resetURL');
-        $this->put('/invite', App\Controllers\UserController::class . ':resetInviteURL');
+    $app->group('/user', function (RouteCollectorProxy $group): void {
+        $group->get('', App\Controllers\UserController::class . ':index');
+        $group->get('/', App\Controllers\UserController::class . ':index');
+
+        $group->post('/checkin', App\Controllers\UserController::class . ':doCheckin');
+
+        $group->get('/announcement', App\Controllers\UserController::class . ':announcement');
+        $group->get('/docs', App\Controllers\UserController::class . ':docs');
+
+        $group->get('/media', App\Controllers\UserController::class . ':media');
+
+        $group->get('/profile', App\Controllers\UserController::class . ':profile');
+        $group->get('/invite', App\Controllers\UserController::class . ':invite');
+        $group->get('/banned', App\Controllers\UserController::class . ':banned');
+
+        $group->get('/server', App\Controllers\User\ServerController::class . ':userServerPage');
+
+        $group->get('/detect', App\Controllers\User\DetectController::class . ':detectIndex');
+        $group->get('/detect/log', App\Controllers\User\DetectController::class . ':detectLog');
+
+        $group->get('/shop', App\Controllers\User\ShopController::class . ':shop');
+        $group->post('/coupon_check', App\Controllers\User\ShopController::class . ':couponCheck');
+        $group->post('/buy', App\Controllers\User\ShopController::class . ':buy');
+        $group->post('/buy_traffic_package', App\Controllers\User\ShopController::class . ':buyTrafficPackage');
+
+        $group->get('/ticket', App\Controllers\User\TicketController::class . ':ticket');
+        $group->get('/ticket/create', App\Controllers\User\TicketController::class . ':ticketCreate');
+        $group->post('/ticket', App\Controllers\User\TicketController::class . ':ticketAdd');
+        $group->get('/ticket/{id}/view', App\Controllers\User\TicketController::class . ':ticketView');
+        $group->put('/ticket/{id}', App\Controllers\User\TicketController::class . ':ticketUpdate');
+
+        $group->post('/buy_invite', App\Controllers\UserController::class . ':buyInvite');
+        $group->post('/custom_invite', App\Controllers\UserController::class . ':customInvite');
+        $group->get('/edit', App\Controllers\UserController::class . ':edit');
+        $group->post('/email', App\Controllers\UserController::class . ':updateEmail');
+        $group->post('/username', App\Controllers\UserController::class . ':updateUsername');
+        $group->post('/password', App\Controllers\UserController::class . ':updatePassword');
+        $group->post('/send', App\Controllers\AuthController::class . ':sendVerify');
+        $group->post('/contact_update', App\Controllers\UserController::class . ':updateContact');
+        $group->post('/ssr', App\Controllers\UserController::class . ':updateSSR');
+        $group->post('/theme', App\Controllers\UserController::class . ':updateTheme');
+        $group->post('/mail', App\Controllers\UserController::class . ':updateMail');
+        $group->post('/passwd_reset', App\Controllers\UserController::class . ':resetPasswd');
+        $group->post('/method', App\Controllers\UserController::class . ':updateMethod');
+        $group->get('/trafficlog', App\Controllers\UserController::class . ':trafficLog');
+        $group->get('/kill', App\Controllers\UserController::class . ':kill');
+        $group->post('/kill', App\Controllers\UserController::class . ':handleKill');
+        $group->get('/logout', App\Controllers\UserController::class . ':logout');
+        $group->get('/backtoadmin', App\Controllers\UserController::class . ':backtoadmin');
+        $group->get('/code', App\Controllers\UserController::class . ':code');
+
+        $group->get('/code_check', App\Controllers\UserController::class . ':codeCheck');
+        $group->post('/code', App\Controllers\UserController::class . ':codePost');
+        $group->post('/ga_check', App\Controllers\UserController::class . ':checkGa');
+        $group->post('/ga_set', App\Controllers\UserController::class . ':setGa');
+        $group->get('/ga_reset', App\Controllers\UserController::class . ':resetGa');
+        $group->post('/telegram_reset', App\Controllers\UserController::class . ':resetTelegram');
+        $group->post('/unblock', App\Controllers\UserController::class . ':unblock');
+        $group->get('/bought', App\Controllers\UserController::class . ':bought');
+        $group->delete('/bought', App\Controllers\UserController::class . ':deleteBoughtGet');
+        $group->post('/url_reset', App\Controllers\UserController::class . ':resetURL');
+        $group->put('/invite', App\Controllers\UserController::class . ':resetInviteURL');
 
         //深色模式
-        $this->post('/switch_theme_mode', App\Controllers\UserController::class . ':switchThemeMode');
+        $group->post('/switch_theme_mode', App\Controllers\UserController::class . ':switchThemeMode');
 
         // 订阅记录
-        $this->get('/subscribe_log', App\Controllers\UserController::class . ':subscribeLog');
+        $group->get('/subscribe_log', App\Controllers\UserController::class . ':subscribeLog');
 
         // getUserAllURL
-        $this->get('/getUserAllURL', App\Controllers\UserController::class . ':getUserAllURL');
+        $group->get('/getUserAllURL', App\Controllers\UserController::class . ':getUserAllURL');
 
-        // 支付
-        $this->post('/payment/purchase/{type}', App\Services\Payment::class . ':purchase');
-        $this->get('/payment/purchase/{type}', App\Services\Payment::class . ':purchase');
-        $this->get('/payment/return/{type}', App\Services\Payment::class . ':returnHTML');
+        //Reconstructed Payment System
+        $group->post('/payment/purchase/{type}', App\Services\Payment::class . ':purchase');
+        $group->get('/payment/purchase/{type}', App\Services\Payment::class . ':purchase');
+        $group->get('/payment/return/{type}', App\Services\Payment::class . ':returnHTML');
     })->add(new Auth());
 
-    $app->group('/payment', function (): void {
-        $this->get('/notify/{type}', App\Services\Payment::class . ':notify');
-        $this->post('/notify/{type}', App\Services\Payment::class . ':notify');
-        $this->post('/status/{type}', App\Services\Payment::class . ':getStatus');
+    $app->group('/payment', function (RouteCollectorProxy $group): void {
+        $group->get('/notify/{type}', App\Services\Payment::class . ':notify');
+        $group->post('/notify/{type}', App\Services\Payment::class . ':notify');
+        $group->post('/status/{type}', App\Services\Payment::class . ':getStatus');
     });
 
     // Auth
-    $app->group('/auth', function (): void {
-        $this->get('/login', App\Controllers\AuthController::class . ':login');
-        $this->post('/qrcode_check', App\Controllers\AuthController::class . ':qrcodeCheck');
-        $this->post('/login', App\Controllers\AuthController::class . ':loginHandle');
-        $this->post('/qrcode_login', App\Controllers\AuthController::class . ':qrcodeLoginHandle');
-        $this->get('/register', App\Controllers\AuthController::class . ':register');
-        $this->post('/register', App\Controllers\AuthController::class . ':registerHandle');
-        $this->post('/send', App\Controllers\AuthController::class . ':sendVerify');
-        $this->get('/logout', App\Controllers\AuthController::class . ':logout');
-        $this->get('/telegram_oauth', App\Controllers\AuthController::class . ':telegramOauth');
+    $app->group('/auth', function (RouteCollectorProxy $group): void {
+        $group->get('/login', App\Controllers\AuthController::class . ':login');
+        $group->post('/qrcode_check', App\Controllers\AuthController::class . ':qrcodeCheck');
+        $group->post('/login', App\Controllers\AuthController::class . ':loginHandle');
+        $group->post('/qrcode_login', App\Controllers\AuthController::class . ':qrcodeLoginHandle');
+        $group->get('/register', App\Controllers\AuthController::class . ':register');
+        $group->post('/register', App\Controllers\AuthController::class . ':registerHandle');
+        $group->post('/send', App\Controllers\AuthController::class . ':sendVerify');
+        $group->get('/logout', App\Controllers\AuthController::class . ':logout');
+        $group->get('/telegram_oauth', App\Controllers\AuthController::class . ':telegramOauth');
     })->add(new Guest());
 
     // Password
-    $app->group('/password', function (): void {
-        $this->get('/reset', App\Controllers\PasswordController::class . ':reset');
-        $this->post('/reset', App\Controllers\PasswordController::class . ':handleReset');
-        $this->get('/token/{token}', App\Controllers\PasswordController::class . ':token');
-        $this->post('/token/{token}', App\Controllers\PasswordController::class . ':handleToken');
+    $app->group('/password', function (RouteCollectorProxy $group): void {
+        $group->get('/reset', App\Controllers\PasswordController::class . ':reset');
+        $group->post('/reset', App\Controllers\PasswordController::class . ':handleReset');
+        $group->get('/token/{token}', App\Controllers\PasswordController::class . ':token');
+        $group->post('/token/{token}', App\Controllers\PasswordController::class . ':handleToken');
     })->add(new Guest());
 
     // Admin
-    $app->group('/admin', function (): void {
-        $this->get('', App\Controllers\AdminController::class . ':index');
-        $this->get('/', App\Controllers\AdminController::class . ':index');
+    $app->group('/admin', function (RouteCollectorProxy $group): void {
+        $group->get('', App\Controllers\AdminController::class . ':index');
+        $group->get('/', App\Controllers\AdminController::class . ':index');
 
-        $this->get('/sys', App\Controllers\AdminController::class . ':sys');
-        $this->get('/invite', App\Controllers\AdminController::class . ':invite');
-        $this->post('/invite', App\Controllers\AdminController::class . ':addInvite');
-        $this->post('/chginvite', App\Controllers\AdminController::class . ':chgInvite');
-        $this->post('/payback/ajax', App\Controllers\AdminController::class . ':ajaxPayback');
+        $group->get('/sys', App\Controllers\AdminController::class . ':sys');
+        $group->get('/invite', App\Controllers\AdminController::class . ':invite');
+        $group->post('/invite', App\Controllers\AdminController::class . ':addInvite');
+        $group->post('/chginvite', App\Controllers\AdminController::class . ':chgInvite');
+        $group->post('/payback/ajax', App\Controllers\AdminController::class . ':ajaxPayback');
 
         // Node Mange
-        $this->get('/node', App\Controllers\Admin\NodeController::class . ':index');
-        $this->get('/node/create', App\Controllers\Admin\NodeController::class . ':create');
-        $this->post('/node', App\Controllers\Admin\NodeController::class . ':add');
-        $this->get('/node/{id}/edit', App\Controllers\Admin\NodeController::class . ':edit');
-        $this->post('/node/{id}/password_reset', App\Controllers\Admin\NodeController::class . ':resetNodePassword');
-        $this->post('/node/{id}/copy', App\Controllers\Admin\NodeController::class . ':copy');
-        $this->put('/node/{id}', App\Controllers\Admin\NodeController::class . ':update');
-        $this->delete('/node/{id}', App\Controllers\Admin\NodeController::class . ':delete');
-        $this->post('/node/ajax', App\Controllers\Admin\NodeController::class . ':ajax');
+        $group->get('/node', App\Controllers\Admin\NodeController::class . ':index');
+        $group->get('/node/create', App\Controllers\Admin\NodeController::class . ':create');
+        $group->post('/node', App\Controllers\Admin\NodeController::class . ':add');
+        $group->get('/node/{id}/edit', App\Controllers\Admin\NodeController::class . ':edit');
+        $group->post('/node/{id}/password_reset', App\Controllers\Admin\NodeController::class . ':resetNodePassword');
+        $group->post('/node/{id}/copy', App\Controllers\Admin\NodeController::class . ':copy');
+        $group->put('/node/{id}', App\Controllers\Admin\NodeController::class . ':update');
+        $group->delete('/node/{id}', App\Controllers\Admin\NodeController::class . ':delete');
+        $group->post('/node/ajax', App\Controllers\Admin\NodeController::class . ':ajax');
 
         // Ticket Mange
-        $this->get('/ticket', App\Controllers\Admin\TicketController::class . ':index');
-        $this->post('/ticket', App\Controllers\Admin\TicketController::class . ':add');
-        $this->get('/ticket/{id}/view', App\Controllers\Admin\TicketController::class . ':ticketView');
-        $this->put('/ticket/{id}/close', App\Controllers\Admin\TicketController::class . ':close');
-        $this->put('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':update');
-        $this->delete('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':delete');
-        $this->post('/ticket/ajax', App\Controllers\Admin\TicketController::class . ':ajax');
+        $group->get('/ticket', App\Controllers\Admin\TicketController::class . ':index');
+        $group->post('/ticket', App\Controllers\Admin\TicketController::class . ':add');
+        $group->get('/ticket/{id}/view', App\Controllers\Admin\TicketController::class . ':ticketView');
+        $group->put('/ticket/{id}/close', App\Controllers\Admin\TicketController::class . ':close');
+        $group->put('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':update');
+        $group->delete('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':delete');
+        $group->post('/ticket/ajax', App\Controllers\Admin\TicketController::class . ':ajax');
 
         // Shop Mange
-        $this->get('/shop', App\Controllers\Admin\ShopController::class . ':index');
-        $this->post('/shop/ajax', App\Controllers\Admin\ShopController::class . ':ajaxShop');
-        $this->get('/shop/create', App\Controllers\Admin\ShopController::class . ':create');
-        $this->post('/shop', App\Controllers\Admin\ShopController::class . ':add');
-        $this->get('/shop/{id}/edit', App\Controllers\Admin\ShopController::class . ':edit');
-        $this->put('/shop/{id}', App\Controllers\Admin\ShopController::class . ':update');
-        $this->delete('/shop', App\Controllers\Admin\ShopController::class . ':deleteGet');
+        $group->get('/shop', App\Controllers\Admin\ShopController::class . ':index');
+        $group->post('/shop/ajax', App\Controllers\Admin\ShopController::class . ':ajaxShop');
+        $group->get('/shop/create', App\Controllers\Admin\ShopController::class . ':create');
+        $group->post('/shop', App\Controllers\Admin\ShopController::class . ':add');
+        $group->get('/shop/{id}/edit', App\Controllers\Admin\ShopController::class . ':edit');
+        $group->put('/shop/{id}', App\Controllers\Admin\ShopController::class . ':update');
+        $group->delete('/shop', App\Controllers\Admin\ShopController::class . ':deleteGet');
 
         // Bought Mange
-        $this->get('/bought', App\Controllers\Admin\ShopController::class . ':bought');
-        $this->delete('/bought', App\Controllers\Admin\ShopController::class . ':deleteBoughtGet');
-        $this->post('/bought/ajax', App\Controllers\Admin\ShopController::class . ':ajaxBought');
+        $group->get('/bought', App\Controllers\Admin\ShopController::class . ':bought');
+        $group->delete('/bought', App\Controllers\Admin\ShopController::class . ':deleteBoughtGet');
+        $group->post('/bought/ajax', App\Controllers\Admin\ShopController::class . ':ajaxBought');
 
         // Ann Mange
-        $this->get('/announcement', App\Controllers\Admin\AnnController::class . ':index');
-        $this->get('/announcement/create', App\Controllers\Admin\AnnController::class . ':create');
-        $this->post('/announcement', App\Controllers\Admin\AnnController::class . ':add');
-        $this->get('/announcement/{id}/edit', App\Controllers\Admin\AnnController::class . ':edit');
-        $this->put('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':update');
-        $this->delete('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':delete');
-        $this->post('/announcement/ajax', App\Controllers\Admin\AnnController::class . ':ajax');
+        $group->get('/announcement', App\Controllers\Admin\AnnController::class . ':index');
+        $group->get('/announcement/create', App\Controllers\Admin\AnnController::class . ':create');
+        $group->post('/announcement', App\Controllers\Admin\AnnController::class . ':add');
+        $group->get('/announcement/{id}/edit', App\Controllers\Admin\AnnController::class . ':edit');
+        $group->put('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':update');
+        $group->delete('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':delete');
+        $group->post('/announcement/ajax', App\Controllers\Admin\AnnController::class . ':ajax');
 
         // Detect Mange
-        $this->get('/detect', App\Controllers\Admin\DetectController::class . ':index');
-        $this->get('/detect/create', App\Controllers\Admin\DetectController::class . ':create');
-        $this->post('/detect', App\Controllers\Admin\DetectController::class . ':add');
-        $this->get('/detect/{id}/edit', App\Controllers\Admin\DetectController::class . ':edit');
-        $this->put('/detect/{id}', App\Controllers\Admin\DetectController::class . ':update');
-        $this->delete('/detect', App\Controllers\Admin\DetectController::class . ':delete');
-        $this->get('/detect/log', App\Controllers\Admin\DetectController::class . ':log');
-        $this->post('/detect/ajax', App\Controllers\Admin\DetectController::class . ':ajaxRule');
-        $this->post('/detect/log/ajax', App\Controllers\Admin\DetectController::class . ':ajaxLog');
+        $group->get('/detect', App\Controllers\Admin\DetectController::class . ':index');
+        $group->get('/detect/create', App\Controllers\Admin\DetectController::class . ':create');
+        $group->post('/detect', App\Controllers\Admin\DetectController::class . ':add');
+        $group->get('/detect/{id}/edit', App\Controllers\Admin\DetectController::class . ':edit');
+        $group->put('/detect/{id}', App\Controllers\Admin\DetectController::class . ':update');
+        $group->delete('/detect', App\Controllers\Admin\DetectController::class . ':delete');
+        $group->get('/detect/log', App\Controllers\Admin\DetectController::class . ':log');
+        $group->post('/detect/ajax', App\Controllers\Admin\DetectController::class . ':ajaxRule');
+        $group->post('/detect/log/ajax', App\Controllers\Admin\DetectController::class . ':ajaxLog');
 
         // IP Mange
-        $this->get('/login', App\Controllers\Admin\IpController::class . ':login');
-        $this->get('/alive', App\Controllers\Admin\IpController::class . ':alive');
-        $this->post('/login/ajax', App\Controllers\Admin\IpController::class . ':ajaxLogin');
-        $this->post('/alive/ajax', App\Controllers\Admin\IpController::class . ':ajaxAlive');
+        $group->get('/login', App\Controllers\Admin\IpController::class . ':login');
+        $group->get('/alive', App\Controllers\Admin\IpController::class . ':alive');
+        $group->post('/login/ajax', App\Controllers\Admin\IpController::class . ':ajaxLogin');
+        $group->post('/alive/ajax', App\Controllers\Admin\IpController::class . ':ajaxAlive');
 
         // Code Mange
-        $this->get('/code', App\Controllers\Admin\CodeController::class . ':index');
-        $this->get('/code/create', App\Controllers\Admin\CodeController::class . ':create');
-        $this->post('/code', App\Controllers\Admin\CodeController::class . ':add');
-        $this->post('/code/ajax', App\Controllers\Admin\CodeController::class . ':ajaxCode');
+        $group->get('/code', App\Controllers\Admin\CodeController::class . ':index');
+        $group->get('/code/create', App\Controllers\Admin\CodeController::class . ':create');
+        $group->post('/code', App\Controllers\Admin\CodeController::class . ':add');
+        $group->post('/code/ajax', App\Controllers\Admin\CodeController::class . ':ajaxCode');
 
         // User Mange
-        $this->get('/user', App\Controllers\Admin\UserController::class . ':index');
-        $this->get('/user/{id}/edit', App\Controllers\Admin\UserController::class . ':edit');
-        $this->put('/user/{id}', App\Controllers\Admin\UserController::class . ':update');
-        $this->post('/user/changetouser', App\Controllers\Admin\UserController::class . ':changetouser');
-        $this->post('/user/create', App\Controllers\Admin\UserController::class . ':createNewUser');
-        $this->delete('/user/{id}', App\Controllers\Admin\UserController::class . ':delete');
-        $this->post('/user/ajax', App\Controllers\Admin\UserController::class . ':ajax');
+        $group->get('/user', App\Controllers\Admin\UserController::class . ':index');
+        $group->get('/user/{id}/edit', App\Controllers\Admin\UserController::class . ':edit');
+        $group->put('/user/{id}', App\Controllers\Admin\UserController::class . ':update');
+        $group->post('/user/changetouser', App\Controllers\Admin\UserController::class . ':changetouser');
+        $group->post('/user/create', App\Controllers\Admin\UserController::class . ':createNewUser');
+        $group->delete('/user/{id}', App\Controllers\Admin\UserController::class . ':delete');
+        $group->post('/user/ajax', App\Controllers\Admin\UserController::class . ':ajax');
 
         // Coupon Mange
-        $this->get('/coupon', App\Controllers\Admin\CouponController::class . ':index');
-        $this->post('/coupon', App\Controllers\Admin\CouponController::class . ':add');
-        $this->post('/coupon/ajax', App\Controllers\Admin\CouponController::class . ':ajax');
-        $this->delete('/coupon/{id}', App\Controllers\Admin\CouponController::class . ':delete');
+        $group->get('/coupon', App\Controllers\AdminController::class . ':coupon');
+        $group->post('/coupon', App\Controllers\AdminController::class . ':addCoupon');
+        $group->post('/coupon/ajax', App\Controllers\AdminController::class . ':ajaxCoupon');
 
         // Subscribe Log Mange
-        $this->get('/subscribe', App\Controllers\Admin\SubscribeLogController::class . ':index');
-        $this->post('/subscribe/ajax', App\Controllers\Admin\SubscribeLogController::class . ':ajaxSubscribeLog');
+        $group->get('/subscribe', App\Controllers\Admin\SubscribeLogController::class . ':index');
+        $group->post('/subscribe/ajax', App\Controllers\Admin\SubscribeLogController::class . ':ajaxSubscribeLog');
 
         // Traffic Log Mange
-        $this->get('/trafficlog', App\Controllers\Admin\TrafficLogController::class . ':index');
-        $this->post('/trafficlog/ajax', App\Controllers\Admin\TrafficLogController::class . ':ajaxTrafficLog');
+        $group->get('/trafficlog', App\Controllers\Admin\TrafficLogController::class . ':index');
+        $group->post('/trafficlog/ajax', App\Controllers\Admin\TrafficLogController::class . ':ajaxTrafficLog');
 
         // Detect Ban Mange
-        $this->get('/detect/ban', App\Controllers\Admin\DetectBanLogController::class . ':index');
-        $this->post('/detect/ban/ajax', App\Controllers\Admin\DetectBanLogController::class . ':ajaxLog');
+        $group->get('/detect/ban', App\Controllers\Admin\DetectBanLogController::class . ':index');
+        $group->post('/detect/ban/ajax', App\Controllers\Admin\DetectBanLogController::class . ':ajaxLog');
 
         // 设置中心
-        $this->get('/setting', App\Controllers\Admin\SettingController::class . ':index');
-        $this->post('/setting', App\Controllers\Admin\SettingController::class . ':save');
-        $this->post('/setting/email', App\Controllers\Admin\SettingController::class . ':test');
-        $this->post('/setting/payment', App\Controllers\Admin\SettingController::class . ':payment');
-
-        // 礼品卡
-        $this->get('/giftcard', App\Controllers\Admin\GiftCardController::class . ':index');
-        $this->post('/giftcard', App\Controllers\Admin\GiftCardController::class . ':add');
-        $this->post('/giftcard/ajax', App\Controllers\Admin\GiftCardController::class . ':ajax');
-        $this->delete('/giftcard/{id}', App\Controllers\Admin\GiftCardController::class . ':delete');
-
-        // 商品
-        $this->get('/product', App\Controllers\Admin\ProductController::class . ':index');
-        $this->get('/product/create', App\Controllers\Admin\ProductController::class . ':create');
-        $this->post('/product', App\Controllers\Admin\ProductController::class . ':add');
-        $this->get('/product/{id}/edit', App\Controllers\Admin\ProductController::class . ':edit');
-        $this->post('/product/{id}/copy', App\Controllers\Admin\ProductController::class . ':copy');
-        $this->put('/product/{id}', App\Controllers\Admin\ProductController::class . ':update');
-        $this->delete('/product/{id}', App\Controllers\Admin\ProductController::class . ':delete');
-        $this->post('/product/ajax', App\Controllers\Admin\ProductController::class . ':ajax');
-
-        // 订单
-        $this->get('/order', App\Controllers\Admin\OrderController::class . ':index');
-        $this->get('/order/{id}/view', App\Controllers\Admin\OrderController::class . ':detail');
-        $this->post('/order/{id}/cancel', App\Controllers\Admin\OrderController::class . ':cancel');
-        $this->delete('/order/{id}', App\Controllers\Admin\OrderController::class . ':delete');
-        $this->post('/order/ajax', App\Controllers\Admin\OrderController::class . ':ajax');
-
-        // 账单
-        $this->get('/invoice', App\Controllers\Admin\InvoiceController::class . ':index');
-        $this->get('/invoice/{id}/view', App\Controllers\Admin\InvoiceController::class . ':detail');
-        $this->post('/invoice/{id}/mark_paid', App\Controllers\Admin\InvoiceController::class . ':markPaid');
-        $this->post('/invoice/ajax', App\Controllers\Admin\InvoiceController::class . ':ajax');
+        $group->get('/setting', App\Controllers\Admin\SettingController::class . ':index');
+        $group->post('/setting', App\Controllers\Admin\SettingController::class . ':save');
+        $group->post('/setting/email', App\Controllers\Admin\SettingController::class . ':test');
+        $group->post('/setting/payment', App\Controllers\Admin\SettingController::class . ':payment');
     })->add(new Admin());
 
-    //$app->group('/admin/api', function (): void {
-    //    $this->post('/{action}', App\Controllers\Api\AdminApiController::class . ':actionHandler');
-    //})->add(new AdminApiToken());
-
-    //$app->group('/user/api', function (): void {
-    //    $this->post('/{action}', App\Controllers\Api\UserApiController::class . ':actionHandler');
-    //})->add(new UserApiToken());
-
-    // WebAPI
-    $app->group('/mod_mu', function (): void {
+    if ($_ENV['enableAdminApi']) {
+        $app->group('/admin/api', function (RouteCollectorProxy $group): void {
+            $group->get('/nodes', App\Controllers\Admin\ApiController::class . ':getNodeList');
+            $group->get('/node/{id}', App\Controllers\Admin\ApiController::class . ':getNodeInfo');
+            $group->get('/ping', App\Controllers\Admin\ApiController::class . ':ping');
+
+            // Re-bind controller, bypass admin token require
+            $group->post('/node', App\Controllers\Admin\NodeController::class . ':add');
+            $group->put('/node/{id}', App\Controllers\Admin\NodeController::class . ':update');
+            $group->delete('/node', App\Controllers\Admin\NodeController::class . ':delete');
+        })->add(new AuthorizationBearer($_ENV['adminApiToken']));
+    }
+
+    // mu
+    $app->group('/mod_mu', function (RouteCollectorProxy $group): void {
         // 流媒体检测
-        $this->post('/media/save_report', App\Controllers\WebAPI\NodeController::class . ':saveReport');
+        $group->post('/media/saveReport', App\Controllers\Node\NodeController::class . ':saveReport');
         // 节点
-        $this->get('/nodes/{id}/info', App\Controllers\WebAPI\NodeController::class . ':getInfo');
+        $group->get('/nodes', App\Controllers\Node\NodeController::class . ':getAllInfo');
+        $group->get('/nodes/{id}/info', App\Controllers\Node\NodeController::class . ':getInfo');
+        $group->post('/nodes/{id}/info', App\Controllers\Node\NodeController::class . ':info');
         // 用户
-        $this->get('/users', App\Controllers\WebAPI\UserController::class . ':index');
-        $this->post('/users/traffic', App\Controllers\WebAPI\UserController::class . ':addTraffic');
-        $this->post('/users/aliveip', App\Controllers\WebAPI\UserController::class . ':addAliveIp');
-        $this->post('/users/detectlog', App\Controllers\WebAPI\UserController::class . ':addDetectLog');
+        $group->get('/users', App\Controllers\Node\UserController::class . ':index');
+        $group->post('/users/traffic', App\Controllers\Node\UserController::class . ':addTraffic');
+        $group->post('/users/aliveip', App\Controllers\Node\UserController::class . ':addAliveIp');
+        $group->post('/users/detectlog', App\Controllers\Node\UserController::class . ':addDetectLog');
         // 审计 & 杂七杂八的功能
-        $this->get('/func/detect_rules', App\Controllers\WebAPI\FuncController::class . ':getDetectLogs');
-        $this->get('/func/ping', App\Controllers\WebAPI\FuncController::class . ':ping');
+        $group->get('/func/detect_rules', App\Controllers\Node\FuncController::class . ':getDetectLogs');
+        $group->get('/func/ping', App\Controllers\Node\FuncController::class . ':ping');
         // Dummy API for old version
-        $this->get('/nodes', App\Controllers\WebAPI\NodeController::class . ':getAllInfo');
-        $this->post('/func/block_ip', App\Controllers\WebAPI\FuncController::class . ':addBlockIp');
-        $this->get('/func/block_ip', App\Controllers\WebAPI\FuncController::class . ':getBlockip');
-        $this->get('/func/unblock_ip', App\Controllers\WebAPI\FuncController::class . ':getUnblockip');
-        $this->post('/nodes/{id}/info', App\Controllers\WebAPI\NodeController::class . ':info');
+        $group->post('/func/block_ip', App\Controllers\Node\FuncController::class . ':addBlockIp');
+        $group->get('/func/block_ip', App\Controllers\Node\FuncController::class . ':getBlockip');
+        $group->get('/func/unblock_ip', App\Controllers\Node\FuncController::class . ':getUnblockip');
     })->add(new NodeToken());
 
-    // 传统订阅(SS/V2Ray/Trojan etc.)
-    $app->group('/link', function (): void {
-        $this->get('/{token}', App\Controllers\LinkController::class . ':getContent');
-    });
+    $app->get('/link/{token}', App\Controllers\LinkController::class . ':getContent');
 
-    // 通用订阅(Json/Clash)
-    $app->group('/sub', function (): void {
-        $this->get('/{token}/{subtype}', App\Controllers\SubController::class . ':getContent');
-    });
+    //通用訂閲
+    $app->get('/sub/{token}/{subtype}', App\Controllers\SubController::class . ':getContent');
 };

+ 5 - 4
composer.json

@@ -1,6 +1,6 @@
 {
     "require": {
-        "php": ">=8.0",
+        "php": "^8.0",
         "ext-curl": "*",
         "ext-json": "*",
         "ext-mysqli": "*",
@@ -10,6 +10,7 @@
         "cloudflare/sdk": "^1",
         "esdeathlove/datatables": "^1.6",
         "guzzlehttp/guzzle": "^7.4",
+        "guzzlehttp/psr7": "^2.4",
         "illuminate/database": "^9.0",
         "illuminate/pagination": "^9.0",
         "irazasyed/telegram-bot-sdk": "^3",
@@ -23,13 +24,13 @@
         "robmorgan/phinx": "^0.13",
         "sendgrid/sendgrid": "^8",
         "sentry/sentry": "^3",
-        "slim/slim": "^3.12",
+        "slim/http": "^1.3",
+        "slim/slim": "^4.11",
         "smarty/smarty": "^4",
         "stripe/stripe-php": "^7",
         "symfony/console": "*",
         "symfony/yaml": "^6",
-        "voku/anti-xss": "^4",
-        "zeuxisoo/slim-whoops": "0.6.*"
+        "voku/anti-xss": "^4"
     },
     "autoload": {
         "psr-4": {

+ 14 - 13
public/index.php

@@ -9,33 +9,34 @@
 
 declare(strict_types=1);
 
-if (PHP_VERSION_ID >= 80100) {
-    error_reporting(E_ALL ^ E_DEPRECATED);
-}
-
 require __DIR__ . '/../vendor/autoload.php';
 require __DIR__ . '/../config/.config.php';
 require __DIR__ . '/../config/appprofile.php';
 require __DIR__ . '/../app/predefine.php';
 require __DIR__ . '/../app/envload.php';
 
-// TODO: legacy boot function
+use App\Middleware\ErrorHandler;
 use App\Services\Boot;
+use GuzzleHttp\Psr7\HttpFactory;
+use GuzzleHttp\Psr7\ServerRequest;
+use Slim\Factory\AppFactory;
+use Slim\Http\Factory\DecoratedResponseFactory;
 
+// TODO: legacy boot function
 Boot::setTime();
 Boot::bootSentry();
 Boot::bootDb();
 
-/** @var Slim\Container $container */
-$container = require __DIR__ . '/../app/container.php';
-$app = new Slim\App($container);
+$guzzle_factory = new HttpFactory();
+$response_factory = new DecoratedResponseFactory($guzzle_factory, $guzzle_factory);
+$app = AppFactory::create($response_factory);
 
-/** @var closure $middleware */
-$middleware = require __DIR__ . '/../app/middleware.php';
-$middleware($app);
+$app->add(new ErrorHandler());
 
-/** @var closure $routes */
+/** @var callable */
 $routes = require __DIR__ . '/../app/routes.php';
 $routes($app);
 
-$app->run();
+$request = ServerRequest::fromGlobals();
+$request = new Slim\Http\ServerRequest($request);
+$app->run($request);

+ 11 - 11
src/Controllers/Admin/AnnController.php

@@ -9,7 +9,7 @@ use App\Models\Ann;
 use App\Models\User;
 use App\Utils\Telegram;
 use League\HTMLToMarkdown\HtmlConverter;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class AnnController extends BaseController
@@ -33,12 +33,12 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$details)
-                ->display('admin/announcement/index.tpl')
+                ->fetch('admin/announcement/index.tpl')
         );
     }
 
@@ -47,12 +47,12 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function create(Request $request, Response $response, array $args)
+    public function create(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('update_field', self::$update_field)
-                ->display('admin/announcement/create.tpl')
+                ->fetch('admin/announcement/create.tpl')
         );
     }
 
@@ -61,7 +61,7 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function add(Request $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args)
     {
         $email_notify_class = (int) $request->getParam('email_notify_class');
         $email_notify = (int) $request->getParam('email_notify');
@@ -115,13 +115,13 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args)
     {
         $ann = Ann::find($args['id']);
         return $response->write(
             $this->view()
                 ->assign('ann', $ann)
-                ->display('admin/announcement/edit.tpl')
+                ->fetch('admin/announcement/edit.tpl')
         );
     }
 
@@ -130,7 +130,7 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args)
     {
         $ann = Ann::find($args['id']);
         $ann->content = $request->getParam('content');
@@ -153,7 +153,7 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function delete(Request $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args)
     {
         $ann = Ann::find($args['id']);
         if (! $ann->delete()) {
@@ -173,7 +173,7 @@ final class AnnController extends BaseController
      *
      * @param array     $args
      */
-    public function ajax(Request $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args)
     {
         $anns = Ann::orderBy('id', 'asc')->get();
 

+ 4 - 4
src/Controllers/Admin/ApiController.php

@@ -7,7 +7,7 @@ namespace App\Controllers\Admin;
 use App\Controllers\BaseController;
 use App\Models\Node;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class ApiController extends BaseController
@@ -15,7 +15,7 @@ final class ApiController extends BaseController
     /**
      * @param array     $args
      */
-    public function getNodeList(Request $request, Response $response, array $args): ResponseInterface
+    public function getNodeList(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->withJson([
             'ret' => 1,
@@ -26,7 +26,7 @@ final class ApiController extends BaseController
     /**
      * @param array     $args
      */
-    public function getNodeInfo(Request $request, Response $response, array $args): ResponseInterface
+    public function getNodeInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node = Node::find($args['id']);
 
@@ -39,7 +39,7 @@ final class ApiController extends BaseController
     /**
      * @param array     $args
      */
-    public function ping(Request $request, Response $response, array $args): ResponseInterface
+    public function ping(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->withJson([
             'ret' => 1,

+ 7 - 7
src/Controllers/Admin/CodeController.php

@@ -11,7 +11,7 @@ use App\Services\Auth;
 use App\Services\Mail;
 use App\Utils\ResponseHelper;
 use App\Utils\Tools;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class CodeController extends BaseController
@@ -21,7 +21,7 @@ final class CodeController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -35,14 +35,14 @@ final class CodeController extends BaseController
                     'user_name' => '用户名',
                     'usedatetime' => '使用时间',
                 ], 'code/ajax'))
-                ->display('admin/code/index.tpl')
+                ->fetch('admin/code/index.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function ajaxCode(Request $request, Response $response, array $args)
+    public function ajaxCode(ServerRequest $request, Response $response, array $args)
     {
         $query = Code::getTableDataFromAdmin(
             $request,
@@ -81,18 +81,18 @@ final class CodeController extends BaseController
     /**
      * @param array     $args
      */
-    public function create(Request $request, Response $response, array $args)
+    public function create(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
-                ->display('admin/code/add.tpl')
+                ->fetch('admin/code/add.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function add(Request $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args)
     {
         $cards = [];
         $user = Auth::getUser();

+ 4 - 4
src/Controllers/Admin/DetectBanLogController.php

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\DetectBanLog;
 use App\Utils\ResponseHelper;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class DetectBanLogController extends BaseController
@@ -16,7 +16,7 @@ final class DetectBanLogController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write(
             $this->view()
@@ -32,14 +32,14 @@ final class DetectBanLogController extends BaseController
                     'ban_end_time' => '封禁结束时间',
                     'all_detect_number' => '累计违规次数',
                 ], 'ban/ajax'))
-                ->display('admin/detect/ban.tpl')
+                ->fetch('admin/detect/ban.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function ajaxLog(Request $request, Response $response, array $args): ResponseInterface
+    public function ajaxLog(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $query = DetectBanLog::getTableDataFromAdmin(
             $request,

+ 14 - 14
src/Controllers/Admin/DetectController.php

@@ -9,7 +9,7 @@ use App\Models\DetectLog;
 use App\Models\DetectRule;
 use App\Utils\ResponseHelper;
 use App\Utils\Telegram;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class DetectController extends BaseController
@@ -17,7 +17,7 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -29,14 +29,14 @@ final class DetectController extends BaseController
                     'regex' => '正则表达式',
                     'type' => '类型',
                 ], 'detect/ajax'))
-                ->display('admin/detect/index.tpl')
+                ->fetch('admin/detect/index.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function ajaxRule(Request $request, Response $response, array $args)
+    public function ajaxRule(ServerRequest $request, Response $response, array $args)
     {
         $query = DetectRule::getTableDataFromAdmin(
             $request,
@@ -73,18 +73,18 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function create(Request $request, Response $response, array $args)
+    public function create(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
-                ->display('admin/detect/add.tpl')
+                ->fetch('admin/detect/add.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function add(Request $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args)
     {
         $rule = new DetectRule();
         $rule->name = $request->getParam('name');
@@ -109,21 +109,21 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $rule = DetectRule::find($id);
         return $response->write(
             $this->view()
                 ->assign('rule', $rule)
-                ->display('admin/detect/edit.tpl')
+                ->fetch('admin/detect/edit.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $rule = DetectRule::find($id);
@@ -149,7 +149,7 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function delete(Request $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args)
     {
         $id = $request->getParam('id');
         $rule = DetectRule::find($id);
@@ -168,7 +168,7 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function log(Request $request, Response $response, array $args)
+    public function log(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -185,14 +185,14 @@ final class DetectController extends BaseController
                     'rule_type' => '规则类型',
                     'datetime' => '时间',
                 ], 'log/ajax'))
-                ->display('admin/detect/log.tpl')
+                ->fetch('admin/detect/log.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function ajaxLog(Request $request, Response $response, array $args)
+    public function ajaxLog(ServerRequest $request, Response $response, array $args)
     {
         $query = DetectLog::getTableDataFromAdmin(
             $request,

+ 7 - 7
src/Controllers/Admin/IpController.php

@@ -9,7 +9,7 @@ use App\Models\Ip;
 use App\Models\LoginIp;
 use App\Utils\QQWry;
 use App\Utils\Tools;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class IpController extends BaseController
@@ -46,12 +46,12 @@ final class IpController extends BaseController
      *
      * @param array     $args
      */
-    public function login(Request $request, Response $response, array $args)
+    public function login(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$login_details)
-                ->display('admin/log/login.tpl')
+                ->fetch('admin/ip/login.tpl')
         );
     }
 
@@ -60,7 +60,7 @@ final class IpController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxLogin(Request $request, Response $response, array $args)
+    public function ajaxLogin(ServerRequest $request, Response $response, array $args)
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;
@@ -90,12 +90,12 @@ final class IpController extends BaseController
      *
      * @param array     $args
      */
-    public function alive(Request $request, Response $response, array $args)
+    public function alive(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$ip_details)
-                ->display('admin/log/alive.tpl')
+                ->fetch('admin/ip/alive.tpl')
         );
     }
 
@@ -104,7 +104,7 @@ final class IpController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxAlive(Request $request, Response $response, array $args)
+    public function ajaxAlive(ServerRequest $request, Response $response, array $args)
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;

+ 12 - 12
src/Controllers/Admin/NodeController.php

@@ -12,7 +12,7 @@ use App\Utils\Telegram;
 use App\Utils\Tools;
 use Exception;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class NodeController extends BaseController
@@ -54,12 +54,12 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$details)
-                ->display('admin/node/index.tpl')
+                ->fetch('admin/node/index.tpl')
         );
     }
 
@@ -68,12 +68,12 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function create(Request $request, Response $response, array $args): ResponseInterface
+    public function create(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write(
             $this->view()
                 ->assign('update_field', self::$update_field)
-                ->display('admin/node/create.tpl')
+                ->fetch('admin/node/create.tpl')
         );
     }
 
@@ -82,7 +82,7 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function add(Request $request, Response $response, array $args): ResponseInterface
+    public function add(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node = new Node();
         $node->name = $request->getParam('name');
@@ -166,7 +166,7 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, array $args): ResponseInterface
+    public function edit(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $node = Node::find($id);
@@ -174,7 +174,7 @@ final class NodeController extends BaseController
             $this->view()
                 ->assign('node', $node)
                 ->assign('update_field', self::$update_field)
-                ->display('admin/node/edit.tpl')
+                ->fetch('admin/node/edit.tpl')
         );
     }
 
@@ -183,7 +183,7 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args): ResponseInterface
+    public function update(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $node = Node::find($id);
@@ -253,7 +253,7 @@ final class NodeController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetNodePassword(Request $request, Response $response, array $args)
+    public function resetNodePassword(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $node = Node::find($id);
@@ -274,7 +274,7 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function delete(Request $request, Response $response, array $args): ResponseInterface
+    public function delete(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $node = Node::find($id);
@@ -340,7 +340,7 @@ final class NodeController extends BaseController
      *
      * @param array     $args
      */
-    public function ajax(Request $request, Response $response, array $args): ResponseInterface
+    public function ajax(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $nodes = Node::orderBy('id', 'desc')->get();
 

+ 2 - 2
src/Controllers/Admin/SettingController.php

@@ -31,7 +31,7 @@ final class SettingController extends BaseController
                 ->assign('settings', $config)
                 ->assign('payment_gateways', self::returnGatewaysList())
                 ->assign('active_payment_gateway', self::returnActiveGateways())
-                ->display('admin/setting.tpl')
+                ->fetch('admin/setting.tpl')
         );
     }
 
@@ -146,7 +146,7 @@ final class SettingController extends BaseController
                 [],
                 []
             );
-        } catch (Exception $e) {
+        } catch (\Throwable $e) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => '测试邮件发送失败',

+ 15 - 15
src/Controllers/Admin/ShopController.php

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\Bought;
 use App\Models\Shop;
 use App\Utils\ResponseHelper;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class ShopController extends BaseController
@@ -18,7 +18,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -33,7 +33,7 @@ final class ShopController extends BaseController
                     'status' => '状态',
                     'period_sales' => '周期销量',
                 ], 'shop/ajax'))
-                ->display('admin/shop/index.tpl')
+                ->fetch('admin/shop/index.tpl')
         );
     }
 
@@ -42,11 +42,11 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function create(Request $request, Response $response, array $args)
+    public function create(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
-                ->display('admin/shop/create.tpl')
+                ->fetch('admin/shop/create.tpl')
         );
     }
 
@@ -55,7 +55,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function add(Request $request, Response $response, array $args)
+    public function add(ServerRequest $request, Response $response, array $args)
     {
         $shop = new Shop();
         $shop->name = $request->getParam('name');
@@ -120,14 +120,14 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, 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)
-                ->display('admin/shop/edit.tpl')
+                ->fetch('admin/shop/edit.tpl')
         );
     }
 
@@ -136,7 +136,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $shop = Shop::find($id);
@@ -210,7 +210,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function deleteGet(Request $request, Response $response, array $args)
+    public function deleteGet(ServerRequest $request, Response $response, array $args)
     {
         $id = $request->getParam('id');
         $shop = Shop::find($id);
@@ -237,7 +237,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function bought(Request $request, Response $response, array $args)
+    public function bought(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -252,7 +252,7 @@ final class ShopController extends BaseController
                     'renew' => '自动续费时间',
                     'auto_reset_bandwidth' => '续费时是否重置流量',
                 ], 'bought/ajax'))
-                ->display('admin/shop/bought.tpl')
+                ->fetch('admin/shop/bought.tpl')
         );
     }
 
@@ -261,7 +261,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function deleteBoughtGet(Request $request, Response $response, array $args)
+    public function deleteBoughtGet(ServerRequest $request, Response $response, array $args)
     {
         $id = $request->getParam('id');
         $shop = Bought::find($id);
@@ -283,7 +283,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxShop(Request $request, Response $response, array $args)
+    public function ajaxShop(ServerRequest $request, Response $response, array $args)
     {
         $query = Shop::getTableDataFromAdmin(
             $request,
@@ -325,7 +325,7 @@ final class ShopController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxBought(Request $request, Response $response, array $args)
+    public function ajaxBought(ServerRequest $request, Response $response, array $args)
     {
         $query = Bought::getTableDataFromAdmin(
             $request,

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

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\UserSubscribeLog;
 use App\Utils\QQWry;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class SubscribeLogController extends BaseController
@@ -33,12 +33,12 @@ final class SubscribeLogController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$details)
-                ->display('admin/subscribe.tpl')
+                ->fetch('admin/subscribe.tpl')
         );
     }
 
@@ -47,7 +47,7 @@ final class SubscribeLogController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxSubscribeLog(Request $request, Response $response, array $args): ResponseInterface
+    public function ajaxSubscribeLog(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;

+ 9 - 9
src/Controllers/Admin/TicketController.php

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\Ticket;
 use App\Models\User;
 use App\Utils\Tools;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 use voku\helper\AntiXSS;
 
@@ -32,12 +32,12 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$details)
-                ->display('admin/ticket/index.tpl')
+                ->fetch('admin/ticket/index.tpl')
         );
     }
 
@@ -46,7 +46,7 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $comment = $request->getParam('comment');
@@ -101,7 +101,7 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function ticketView(Request $request, Response $response, array $args)
+    public function ticketView(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->first();
@@ -116,7 +116,7 @@ final class TicketController extends BaseController
                 ->assign('ticket', $ticket)
                 ->assign('comments', $comments)
                 ->registerClass('Tools', Tools::class)
-                ->display('admin/ticket/view.tpl')
+                ->fetch('admin/ticket/view.tpl')
         );
     }
 
@@ -125,7 +125,7 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function close(Request $request, Response $response, array $args)
+    public function close(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->first();
@@ -161,7 +161,7 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function delete(Request $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         Ticket::where('id', '=', $id)->delete();
@@ -177,7 +177,7 @@ final class TicketController extends BaseController
      *
      * @param array     $args
      */
-    public function ajax(Request $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args)
     {
         $tickets = Ticket::orderBy('id', 'desc')->get();
 

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

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\UserHourlyUsage;
 use App\Utils\Tools;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class TrafficLogController extends BaseController
@@ -29,12 +29,12 @@ final class TrafficLogController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write(
             $this->view()
                 ->assign('details', self::$details)
-                ->display('admin/log/traffic.tpl')
+                ->fetch('admin/trafficlog.tpl')
         );
     }
 
@@ -43,7 +43,7 @@ final class TrafficLogController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxTrafficLog(Request $request, Response $response, array $args): ResponseInterface
+    public function ajaxTrafficLog(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $length = $request->getParam('length');
         $page = $request->getParam('start') / $length + 1;

+ 10 - 10
src/Controllers/Admin/UserController.php

@@ -14,7 +14,7 @@ use App\Utils\Check;
 use App\Utils\Cookie;
 use App\Utils\Hash;
 use App\Utils\Tools;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class UserController extends BaseController
@@ -94,20 +94,20 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('shops', Shop::orderBy('name')->get())
                 ->assign('details', self::$details)
-                ->display('admin/user/index.tpl')
+                ->fetch('admin/user/index.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function createNewUser(Request $request, Response $response, array $args)
+    public function createNewUser(ServerRequest $request, Response $response, array $args)
     {
         $email = $request->getParam('email');
         $ref_by = $request->getParam('ref_by');
@@ -170,21 +170,21 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args)
     {
         $user = User::find($args['id']);
         return $response->write(
             $this->view()
                 ->assign('update_field', self::$update_field)
                 ->assign('edit_user', $user)
-                ->display('admin/user/edit.tpl')
+                ->fetch('admin/user/edit.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function update(Request $request, Response $response, array $args)
+    public function update(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $user = User::find($id);
@@ -236,7 +236,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function delete(Request $request, Response $response, array $args)
+    public function delete(ServerRequest $request, Response $response, array $args)
     {
         $id = $args['id'];
         $user = User::find((int) $id);
@@ -257,7 +257,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function changetouser(Request $request, Response $response, array $args)
+    public function changetouser(ServerRequest $request, Response $response, array $args)
     {
         $userid = $request->getParam('userid');
         $adminid = $request->getParam('adminid');
@@ -295,7 +295,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function ajax(Request $request, Response $response, array $args)
+    public function ajax(ServerRequest $request, Response $response, array $args)
     {
         $users = User::orderBy('id', 'desc')->get();
 

+ 14 - 14
src/Controllers/AdminController.php

@@ -11,7 +11,7 @@ use App\Utils\DatatablesHelper;
 use App\Utils\ResponseHelper;
 use App\Utils\Tools;
 use Ozdemir\Datatables\Datatables;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 /*
@@ -24,12 +24,12 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
                 ->assign('sts', new Analytics())
-                ->display('admin/index.tpl')
+                ->fetch('admin/index.tpl')
         );
     }
 
@@ -38,11 +38,11 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function sys(Request $request, Response $response, array $args)
+    public function sys(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
-                ->display('admin/index.tpl')
+                ->fetch('admin/index.tpl')
         );
     }
 
@@ -51,7 +51,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function invite(Request $request, Response $response, array $args)
+    public function invite(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -65,7 +65,7 @@ final class AdminController extends BaseController
                     'ref_get' => '获利金额',
                     'datetime' => '时间',
                 ], 'payback/ajax'))
-                ->display('admin/invite.tpl')
+                ->fetch('admin/invite.tpl')
         );
     }
 
@@ -74,7 +74,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxPayback(Request $request, Response $response, array $args)
+    public function ajaxPayback(ServerRequest $request, Response $response, array $args)
     {
         $datatables = new Datatables(new DatatablesHelper());
         $datatables->query('Select payback.id,payback.total,payback.userid as event_user_id,event_user.user_name as event_user_name,payback.ref_by as ref_user_id,ref_user.user_name as ref_user_name,payback.ref_get,payback.datetime from payback,user as event_user,user as ref_user where event_user.id = payback.userid and ref_user.id = payback.ref_by');
@@ -91,7 +91,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function chgInvite(Request $request, Response $response, array $args)
+    public function chgInvite(ServerRequest $request, Response $response, array $args)
     {
         $userid = $request->getParam('userid');
         if ($userid === null) {
@@ -124,7 +124,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function addInvite(Request $request, Response $response, array $args)
+    public function addInvite(ServerRequest $request, Response $response, array $args)
     {
         $num = $request->getParam('num');
         if (Tools::isInt($num) === false) {
@@ -162,7 +162,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function coupon(Request $request, Response $response, array $args)
+    public function coupon(ServerRequest $request, Response $response, array $args)
     {
         return $response->write(
             $this->view()
@@ -174,7 +174,7 @@ final class AdminController extends BaseController
                     'credit' => '额度',
                     'onetime' => '次数',
                 ], 'coupon/ajax'))
-                ->display('admin/coupon.tpl')
+                ->fetch('admin/coupon.tpl')
         );
     }
 
@@ -183,7 +183,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function ajaxCoupon(Request $request, Response $response, array $args)
+    public function ajaxCoupon(ServerRequest $request, Response $response, array $args)
     {
         $datatables = new Datatables(new DatatablesHelper());
         $datatables->query('Select id,code,expire,shop,credit,onetime from coupon');
@@ -200,7 +200,7 @@ final class AdminController extends BaseController
      *
      * @param array     $args
      */
-    public function addCoupon(Request $request, Response $response, array $args)
+    public function addCoupon(ServerRequest $request, Response $response, array $args)
     {
         $generate_type = (int) $request->getParam('generate_type');
         $final_code = $request->getParam('prefix');

+ 26 - 25
src/Controllers/AuthController.php

@@ -18,8 +18,9 @@ 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\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 use voku\helper\AntiXSS;
 
@@ -31,7 +32,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function login(Request $request, Response $response, array $args)
+    public function login(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $captcha = [];
 
@@ -49,23 +50,23 @@ final class AuthController extends BaseController
             $login_number = '';
         }
 
-        return $this->view()
+        return $response->write($this->view()
             ->assign('login_token', $login_token)
             ->assign('login_number', $login_number)
             ->assign('base_url', $_ENV['baseUrl'])
             ->assign('telegram_bot', $_ENV['telegram_bot'])
             ->assign('captcha', $captcha)
-            ->display('auth/login.tpl');
+            ->fetch('auth/login.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function loginHandle(Request $request, Response $response, array $args)
+    public function loginHandle(ServerRequest $request, Response $response, array $args)
     {
         if (Setting::obtain('enable_login_captcha') === true) {
             $ret = Captcha::verify($request->getParams());
-            if (! $ret) {
+            if (!$ret) {
                 return $response->withJson([
                     'ret' => 0,
                     'msg' => '系统无法接受您的验证结果,请刷新页面后重试。',
@@ -86,7 +87,7 @@ final class AuthController extends BaseController
             ]);
         }
 
-        if (! Hash::checkPassword($user->pass, $passwd)) {
+        if (!Hash::checkPassword($user->pass, $passwd)) {
             // 记录登录失败
             $user->collectLoginIP($_SERVER['REMOTE_ADDR'], 1);
             return $response->withJson([
@@ -98,7 +99,7 @@ final class AuthController extends BaseController
         if ($user->ga_enable === 1) {
             $ga = new GA();
             $rcode = $ga->verifyCode($user->ga_token, $code);
-            if (! $rcode) {
+            if (!$rcode) {
                 return $response->withJson([
                     'ret' => 0,
                     'msg' => '两步验证码错误,如果您是丢失了生成器或者错误地设置了这个选项,您可以尝试重置密码,即可取消这个选项。',
@@ -124,7 +125,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function qrcodeLoginHandle(Request $request, Response $response, array $args)
+    public function qrcodeLoginHandle(ServerRequest $request, Response $response, array $args)
     {
         $token = $request->getParam('token');
         $number = $request->getParam('number');
@@ -145,7 +146,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function register(Request $request, Response $response, $next)
+    public function register(ServerRequest $request, Response $response, $next)
     {
         $captcha = [];
 
@@ -170,7 +171,7 @@ final class AuthController extends BaseController
             $login_number = '';
         }
 
-        return $this->view()
+        return $response->write($this->view()
             ->assign('code', $code)
             ->assign('base_url', $_ENV['baseUrl'])
             ->assign('login_token', $login_token)
@@ -178,13 +179,13 @@ final class AuthController extends BaseController
             ->assign('telegram_bot', $_ENV['telegram_bot'])
             ->assign('enable_email_verify', Setting::obtain('reg_email_verify'))
             ->assign('captcha', $captcha)
-            ->display('auth/register.tpl');
+            ->fetch('auth/register.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function sendVerify(Request $request, Response $response, $next)
+    public function sendVerify(ServerRequest $request, Response $response, $next)
     {
         if (Setting::obtain('reg_email_verify')) {
             $email = trim($request->getParam('email'));
@@ -240,7 +241,7 @@ final class AuthController extends BaseController
     }
 
     /**
-     * @param Request   $request
+     * @param ServerRequest   $request
      * @param Response  $response
      * @param array     $args
      */
@@ -357,7 +358,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function registerHandle(Request $request, Response $response, array $args)
+    public function registerHandle(ServerRequest $request, Response $response, array $args)
     {
         if (Setting::obtain('reg_mode') === 'close') {
             return ResponseHelper::error($response, '未开放注册。');
@@ -365,7 +366,7 @@ final class AuthController extends BaseController
 
         if (Setting::obtain('enable_reg_captcha') === true) {
             $ret = Captcha::verify($request->getParams());
-            if (! $ret) {
+            if (!$ret) {
                 return ResponseHelper::error($response, '系统无法接受您的验证结果,请刷新页面后重试。');
             }
         }
@@ -435,7 +436,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function logout(Request $request, Response $response, $next)
+    public function logout(ServerRequest $request, Response $response, $next)
     {
         Auth::logout();
         return $response->withStatus(302)
@@ -445,7 +446,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function qrcodeCheck(Request $request, Response $response, array $args)
+    public function qrcodeCheck(ServerRequest $request, Response $response, array $args)
     {
         $token = $request->getParam('token');
         $number = $request->getParam('number');
@@ -465,7 +466,7 @@ final class AuthController extends BaseController
     /**
      * @param array     $args
      */
-    public function telegramOauth(Request $request, Response $response, array $args)
+    public function telegramOauth(ServerRequest $request, Response $response, array $args)
     {
         if ($_ENV['enable_telegram_login'] === true) {
             $auth_data = $request->getQueryParams();
@@ -473,26 +474,26 @@ final class AuthController extends BaseController
                 $telegram_id = $auth_data['id'];
                 $user = User::query()->where('telegram_id', $telegram_id)->firstOrFail(); // Welcome Back :)
                 if ($user === null) {
-                    return $this->view()
+                    return $response->write($this->view()
                         ->assign('title', '您需要先进行邮箱注册后绑定Telegram才能使用授权登录')
                         ->assign('message', '很抱歉带来的不便,请重新试试')
                         ->assign('redirect', '/auth/login')
-                        ->display('telegram_error.tpl');
+                        ->fetch('telegram_error.tpl'));
                 }
                 Auth::login($user->id, 3600);
                 $user->collectLoginIP($_SERVER['REMOTE_ADDR']);
 
-                return $this->view()
+                return $response->write($this->view()
                     ->assign('title', '登录成功')
                     ->assign('message', '正在前往仪表盘')
                     ->assign('redirect', '/user')
-                    ->display('telegram_success.tpl');
+                    ->fetch('telegram_success.tpl'));
             }
-            return $this->view()
+            return $response->write($this->view()
                 ->assign('title', '登陆超时或非法构造信息')
                 ->assign('message', '很抱歉带来的不便,请重新试试')
                 ->assign('redirect', '/auth/login')
-                ->display('telegram_error.tpl');
+                ->fetch('telegram_error.tpl'));
         }
         return $response->withRedirect('/404');
     }

+ 9 - 9
src/Controllers/HomeController.php

@@ -8,7 +8,7 @@ use App\Models\InviteCode;
 use App\Services\Auth;
 use App\Utils\Telegram\Process;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 /**
@@ -19,7 +19,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write($this->view()->fetch('index.tpl'));
     }
@@ -27,7 +27,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function code(Request $request, Response $response, array $args): ResponseInterface
+    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'));
@@ -36,7 +36,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function tos(Request $request, Response $response, array $args): ResponseInterface
+    public function tos(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write($this->view()->fetch('tos.tpl'));
     }
@@ -44,7 +44,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function staff(Request $request, Response $response, array $args): ResponseInterface
+    public function staff(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = Auth::getUser();
         if (! $user->isLogin) {
@@ -56,7 +56,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function telegram(Request $request, Response $response, array $args): ResponseInterface
+    public function telegram(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $token = $request->getQueryParam('token');
         if ($token === $_ENV['telegram_request_token']) {
@@ -71,7 +71,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function page404(Request $request, Response $response, array $args): ResponseInterface
+    public function page404(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write($this->view()->fetch('404.tpl'));
     }
@@ -79,7 +79,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function page405(Request $request, Response $response, array $args): ResponseInterface
+    public function page405(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write($this->view()->fetch('405.tpl'));
     }
@@ -87,7 +87,7 @@ final class HomeController extends BaseController
     /**
      * @param array     $args
      */
-    public function page500(Request $request, Response $response, array $args): ResponseInterface
+    public function page500(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return $response->write($this->view()->fetch('500.tpl'));
     }

+ 740 - 198
src/Controllers/LinkController.php

@@ -2,284 +2,826 @@
 
 declare(strict_types=1);
 
+//Thanks to http://blog.csdn.net/jollyjumper/article/details/9823047
+
 namespace App\Controllers;
 
 use App\Models\Link;
-use App\Models\Node;
+use App\Models\User;
+
 use App\Models\UserSubscribeLog;
+use App\Utils\AppURI;
+use App\Utils\ConfGenerate;
+use App\Utils\ConfRender;
+use App\Utils\Tools;
+use App\Utils\URL;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
+use voku\helper\AntiXSS;
 
 /**
  *  LinkController
  */
 final class LinkController extends BaseController
 {
-    public static function getContent(Request $request, Response $response, array $args): ResponseInterface
+    public static function generateRandomLink()
+    {
+        for ($i = 0; $i < 10; $i++) {
+            $token = Tools::genRandomChar(16);
+            $Elink = Link::where('token', $token)->first();
+            if ($Elink === null) {
+                return $token;
+            }
+        }
+
+        return "couldn't alloc token";
+    }
+
+    public static function generateSSRSubCode(int $userid): string
+    {
+        $Elink = Link::where('userid', $userid)->first();
+        if ($Elink !== null) {
+            return $Elink->token;
+        }
+        $NLink = new Link();
+        $NLink->userid = $userid;
+        $NLink->token = self::generateRandomLink();
+        $NLink->save();
+
+        return $NLink->token;
+    }
+
+    /**
+     * @param array     $args
+     */
+    public static function getContent(ServerRequest $request, Response $response, array $args)
     {
         if (! $_ENV['Subscribe']) {
-            return $response->withJson([
-                'ret' => 0,
-            ]);
+            return null;
         }
 
         $token = $args['token'];
-        $params = $request->getQueryParams();
 
         $Elink = Link::where('token', $token)->first();
         if ($Elink === null) {
-            return $response->withJson([
-                'ret' => 0,
-            ]);
+            return null;
         }
 
         $user = $Elink->getUser();
         if ($user === null) {
-            return $response->withJson([
-                'ret' => 0,
-            ]);
+            return null;
         }
 
-        $sub_info = [];
+        $opts = $request->getQueryParams();
 
-        if (isset($params['clash']) && $params['clash'] === '1') {
-            $sub_type = 'clash';
-            $sub_info = SubController::getClash($user);
+        // 筛选节点部分
+        $Rule = [];
+        $Rule['type'] = (isset($opts['type']) ? trim($opts['type']) : 'all');
+        $Rule['is_mu'] = ($_ENV['mergeSub'] === true ? 1 : 0);
+        if (isset($opts['mu'])) {
+            $Rule['is_mu'] = (int) $opts['mu'];
         }
 
-        if (isset($params['sip002']) && $params['sip002'] === '1') {
-            $sub_type = 'sip002';
-            $sub_info = self::getSIP002($user);
+        if (isset($opts['class'])) {
+            $class = trim(urldecode($opts['class']));
+            $Rule['content']['class'] = array_map(
+                static function ($item) {
+                    return (int) $item;
+                },
+                explode('-', $class)
+            );
         }
 
-        if (isset($params['ss']) && $params['ss'] === '1') {
-            $sub_type = 'ss';
-            $sub_info = self::getSS($user);
+        if (isset($opts['noclass'])) {
+            $noclass = trim(urldecode($opts['noclass']));
+            $Rule['content']['noclass'] = array_map(
+                static function ($item) {
+                    return (int) $item;
+                },
+                explode('-', $noclass)
+            );
         }
 
-        if (isset($params['v2ray']) && $params['v2ray'] === '1') {
-            $sub_type = 'v2ray';
-            $sub_info = self::getV2Ray($user);
+        if (isset($opts['regex'])) {
+            $Rule['content']['regex'] = trim(urldecode($opts['regex']));
         }
 
-        if (isset($params['trojan']) && $params['trojan'] === '1') {
-            $sub_type = 'trojan';
-            $sub_info = self::getTrojan($user);
+        // 显示流量以及到期时间等
+        $Rule['extend'] = $_ENV['enable_sub_extend'];
+        if (isset($opts['extend'])) {
+            $Rule['extend'] = (bool) $opts['extend'];
         }
 
-        if (isset($params['sub'])) {
-            switch ($params['sub']) {
-                case '2':
-                    $sub_type = 'ss';
-                    $sub_info = self::getSS($user);
+        // 兼容原版
+        if (isset($opts['mu'])) {
+            $mu = (int) $opts['mu'];
+            switch ($mu) {
+                case 0:
+                    $opts['sub'] = 1;
                     break;
-                case '3':
-                    $sub_type = 'v2ray';
-                    $sub_info = self::getV2Ray($user);
+                case 1:
+                    $opts['sub'] = 1;
                     break;
-                case '4':
-                    $sub_type = 'trojan';
-                    $sub_info = self::getTrojan($user);
+                case 2:
+                    $opts['sub'] = 3;
                     break;
-                default:
-                    $sub_type = 'ss';
-                    $sub_info = self::getSS($user);
+                case 3:
+                    $opts['ssd'] = 1; //deprecated
+                    break;
+                case 4:
+                    $opts['clash'] = 1;
+                    break;
+            }
+        }
+
+        // 订阅类型
+        $subscribe_type = '';
+
+        $getBody = '';
+
+        $sub_type_array = ['list', 'clash', 'surge', 'surfboard','anxray', 'quantumult', 'quantumultx', 'sub'];
+        foreach ($sub_type_array as $key) {
+            if (isset($opts[$key])) {
+                $query_value = $opts[$key];
+                if ($query_value !== '0' && $query_value !== '') {
+                    // 兼容代码开始
+                    if ($key === 'sub' && $query_value > 4) {
+                        $query_value = 1;
+                    }
+                    // 兼容代码结束
+
+                    if ($key === 'list') {
+                        $SubscribeExtend = self::getSubscribeExtend($query_value);
+                    } else {
+                        $SubscribeExtend = self::getSubscribeExtend($key, $query_value);
+                    }
+                    $filename = $SubscribeExtend['filename'] . '_' . \time() . '.' . $SubscribeExtend['suffix'];
+                    $subscribe_type = $SubscribeExtend['filename'];
+
+                    $class = 'get' . $SubscribeExtend['class'];
+                    $content = self::$class($user, $query_value, $opts, $Rule);
+                    $getBody = self::getBody(
+                        $user,
+                        $response,
+                        $content,
+                        $filename
+                    );
                     break;
+                }
+                continue;
             }
         }
 
         // 记录订阅日志
         if ($_ENV['subscribeLog'] === true) {
-            UserSubscribeLog::addSubscribeLog($user, $sub_type, $request->getHeaderLine('User-Agent'));
+            self::subscribeLog($user, $subscribe_type, $request->getHeaderLine('User-Agent'));
         }
 
-        $sub_details = ' upload=' . $user->u
-            . '; download=' . $user->d
-            . '; total=' . $user->transfer_enable
-            . '; expire=' . strtotime($user->class_expire);
+        return $response->write($getBody);
+    }
+
+    /**
+     * 获取订阅类型的文件名
+     *
+     * @param string      $type  订阅类型
+     * @param string|null $value 值
+     *
+     * @return array
+     */
+    public static function getSubscribeExtend(string $type, ?string $value = null): array
+    {
+        switch ($type) {
+            case 'ss':
+                $return = [
+                    'filename' => 'SS',
+                    'suffix' => 'txt',
+                    'class' => 'Sub',
+                ];
+                break;
+            case 'ssa':
+                $return = [
+                    'filename' => 'SSA',
+                    'suffix' => 'json',
+                    'class' => 'Lists',
+                ];
+                break;
+            case 'ssr':
+                $return = [
+                    'filename' => 'SSR',
+                    'suffix' => 'txt',
+                    'class' => 'Sub',
+                ];
+                break;
+            case 'sub':
+                $strArray = [
+                    1 => 'ssr',
+                    2 => 'ss',
+                    3 => 'v2rayn',
+                    4 => 'trojan',
+                ];
+                $str = (! \in_array($value, $strArray) ? $strArray[$value] : $strArray[1]);
+                $return = self::getSubscribeExtend($str);
+                break;
+            case 'clash':
+                if ($value !== null) {
+                    $return = self::getSubscribeExtend('clash');
+                    $return['class'] = 'Clash';
+                } else {
+                    $return = [
+                        'filename' => 'Clash',
+                        'suffix' => 'yaml',
+                        'class' => 'Lists',
+                    ];
+                }
+                break;
+            case 'surge':
+                if ($value !== null) {
+                    $return = [
+                        'filename' => 'Surge',
+                        'suffix' => 'conf',
+                        'class' => 'Surge',
+                    ];
+                    $return['filename'] .= $value;
+                } else {
+                    $return = [
+                        'filename' => 'SurgeList',
+                        'suffix' => 'list',
+                        'class' => 'Lists',
+                    ];
+                }
+                break;
+            case 'v2rayn':
+                $return = [
+                    'filename' => 'V2RayN',
+                    'suffix' => 'txt',
+                    'class' => 'Sub',
+                ];
+                break;
+            case 'trojan':
+                $return = [
+                    'filename' => 'Trojan',
+                    'suffix' => 'txt',
+                    'class' => 'Sub',
+                ];
+                break;
+            case 'kitsunebi':
+                $return = [
+                    'filename' => 'Kitsunebi',
+                    'suffix' => 'txt',
+                    'class' => 'Lists',
+                ];
+                break;
+            case 'anxray':
+                $return = [
+                    'filename' => 'AnXray',
+                    'suffix' => 'txt',
+                    'class' => 'AnXray',
+                ];
+                break;
+            case 'surfboard':
+                $return = [
+                    'filename' => 'Surfboard',
+                    'suffix' => 'conf',
+                    'class' => 'Surfboard',
+                ];
+                break;
+            case 'quantumult':
+                if ($value !== null) {
+                    if ((int) $value === 2) {
+                        $return = self::getSubscribeExtend('quantumult_sub');
+                    } else {
+                        $return = self::getSubscribeExtend('quantumult_conf');
+                    }
+                } else {
+                    $return = [
+                        'filename' => 'Quantumult',
+                        'suffix' => 'conf',
+                        'class' => 'Lists',
+                    ];
+                }
+                break;
+            case 'quantumultx':
+                $return = [
+                    'filename' => 'QuantumultX',
+                    'suffix' => 'txt',
+                    'class' => 'Lists',
+                ];
+                if ($value !== null) {
+                    $return['class'] = 'QuantumultX';
+                }
+                break;
+            case 'shadowrocket':
+                $return = [
+                    'filename' => 'Shadowrocket',
+                    'suffix' => 'txt',
+                    'class' => 'Lists',
+                ];
+                break;
+            case 'clash_provider':
+                $return = [
+                    'filename' => 'ClashProvider',
+                    'suffix' => 'yaml',
+                    'class' => 'Lists',
+                ];
+                break;
+            case 'quantumult_sub':
+                $return = [
+                    'filename' => 'QuantumultSub',
+                    'suffix' => 'conf',
+                    'class' => 'Quantumult',
+                ];
+                break;
+            case 'quantumult_conf':
+                $return = [
+                    'filename' => 'QuantumultConf',
+                    'suffix' => 'conf',
+                    'class' => 'Quantumult',
+                ];
+                break;
+            default:
+                $return = [
+                    'filename' => 'UndefinedNode',
+                    'suffix' => 'txt',
+                    'class' => 'Sub',
+                ];
+                break;
+        }
+        return $return;
+    }
 
-        return $response->withHeader('Subscription-Userinfo', $sub_details)->write(
-            $sub_info
+    /**
+     * 响应内容
+     *
+     * @param string $content  订阅内容
+     * @param string $filename 文件名
+     */
+    public static function getBody(User $user, object $response, string $content, string $filename): ResponseInterface
+    {
+        $response = $response
+            ->withHeader(
+                'Content-type',
+                ' application/octet-stream; charset=utf-8'
+            )
+            ->withHeader(
+                'Cache-Control',
+                'no-store, no-cache, must-revalidate'
+            )
+            ->withHeader(
+                'Content-Disposition',
+                ' attachment; filename=' . $filename
+            )
+            ->withHeader(
+                'Subscription-Userinfo',
+                (' upload=' . $user->u
+                    . '; download=' . $user->d
+                    . '; total=' . $user->transfer_enable
+                    . '; expire=' . strtotime($user->class_expire))
+            );
+
+        return $response->write($content);
+    }
+
+    /**
+     * 订阅链接汇总
+     *
+     * @param User $user 用户
+     * @param int  $int  当前用户访问的订阅类型
+     *
+     * @return array
+     */
+    public static function getSubinfo(User $user, int $int = 0): array
+    {
+        if ($int === 0) {
+            $int = '';
+        }
+        $userapiUrl = $_ENV['subUrl'] . '/link/' . self::generateSSRSubCode($user->id);
+        $return_info = [
+            'link' => '',
+            // sub
+            'ss' => '?sub=2',
+            'ssr' => '?sub=1',
+            'v2ray' => '?sub=3',
+            'trojan' => '?sub=4',
+            // apps
+            'ssa' => '?list=ssa',
+            'anxray' => '?anxray=1',
+            'clash' => '?clash=1',
+            'clash_provider' => '?list=clash',
+            'surge' => '?surge=' . $int,
+            'surge_node' => '?list=surge',
+            'surge2' => '?surge=2',
+            'surge3' => '?surge=3',
+            'surge4' => '?surge=4',
+            'surfboard' => '?surfboard=1',
+            'quantumult' => '?quantumult=' . $int,
+            'quantumult_v2' => '?list=quantumult',
+            'quantumult_sub' => '?quantumult=2',
+            'quantumult_conf' => '?quantumult=3',
+            'quantumultx' => '?list=quantumultx',
+            'shadowrocket' => '?list=shadowrocket',
+            'kitsunebi' => '?list=kitsunebi',
+        ];
+
+        return array_map(
+            static function ($item) use ($userapiUrl) {
+                return $userapiUrl . $item;
+            },
+            $return_info
         );
     }
 
-    // 传统 SS 订阅
-    public static function getSS($user): string
+    public static function getListItem($item, $list)
     {
-        $links = '';
-        //篩選出用戶能連接的節點
-        $nodes_raw = Node::where('type', 1)
-            ->where('node_class', '<=', $user->class)
-            ->whereIn('node_group', [0, $user->node_group])
-            ->where(static function ($query): void {
-                $query->where('node_bandwidth_limit', '=', 0)->orWhereRaw('node_bandwidth < node_bandwidth_limit');
-            })
-            ->get();
-
-        foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
-            //檢查是否配置“前端/订阅中下发的服务器地址”
-            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) . '#' .
-                    $node_raw->name . PHP_EOL;
+        $return = null;
+        switch ($list) {
+            case 'ss':
+                $return = AppURI::getItemUrl($item, 1);
+                break;
+            case 'ssr':
+                $return = AppURI::getItemUrl($item, 0);
+                break;
+            case 'ssa':
+                $return = AppURI::getSSJSON($item);
+                break;
+            case 'anxray':
+                $return = AppURI::getAnXrayURI($item);
+                break;
+            case 'surge':
+                $return = AppURI::getSurgeURI($item, 3);
+                break;
+            case 'clash':
+                $return = AppURI::getClashURI($item);
+                break;
+            case 'v2rayn':
+                $return = AppURI::getV2RayNURI($item);
+                break;
+            case 'trojan':
+                $return = AppURI::getTrojanURI($item);
+                break;
+            case 'kitsunebi':
+                $return = AppURI::getKitsunebiURI($item);
+                break;
+            case 'quantumult':
+                $return = AppURI::getQuantumultURI($item, true);
+                break;
+            case 'quantumultx':
+                $return = AppURI::getQuantumultXURI($item);
+                break;
+            case 'shadowrocket':
+                $return = AppURI::getShadowrocketURI($item);
+                break;
+        }
+        return $return;
+    }
+
+    public static function getLists($user, $list, $opts, $Rule)
+    {
+        $list = strtolower($list);
+        if ($list === 'ssa') {
+            $Rule['type'] = 'ss';
+        }
+        if ($list === 'quantumult') {
+            $Rule['type'] = 'vmess';
+        }
+        $items = URL::getNewAllItems($user, $Rule);
+        $return = [];
+        if ($Rule['extend'] === true) {
+            switch ($list) {
+                case 'ssa':
+                case 'clash':
+                    $return = array_merge($return, self::getListExtend($user, $list));
+                    break;
+                default:
+                    $return[] = implode(PHP_EOL, self::getListExtend($user, $list));
                     break;
             }
         }
-
-        return $links;
+        foreach ($items as $item) {
+            $out = self::getListItem($item, $list);
+            if ($out !== null) {
+                $return[] = $out;
+            }
+        }
+        switch ($list) {
+            case 'ssa':
+                return \json_encode($return, 320);
+                break;
+            case 'clash':
+                return \Symfony\Component\Yaml\Yaml::dump(['proxies' => $return], 4, 2);
+            case 'kitsunebi':
+            case 'quantumult':
+            case 'shadowrocket':
+                return base64_encode(implode(PHP_EOL, $return));
+            default:
+                return implode(PHP_EOL, $return);
+        }
     }
 
-    // SIP002 SS 订阅
-    public static function getSIP002($user): string
+    public static function getListExtend($user, $list)
     {
-        $links = '';
-        //篩選出用戶能連接的節點
-        $nodes_raw = Node::where('type', 1)
-            ->where('node_class', '<=', $user->class)
-            ->whereIn('node_group', [0, $user->node_group])
-            ->where(static function ($query): void {
-                $query->where('node_bandwidth_limit', '=', 0)->orWhereRaw('node_bandwidth < node_bandwidth_limit');
-            })
-            ->get();
-
-        foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
-            //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
-                $server = $node_raw->server;
+        $return = [];
+        $info_array = (count($_ENV['sub_message']) !== 0 ? (array) $_ENV['sub_message'] : []);
+        if (strtotime($user->expire_in) > \time()) {
+            if ($user->transfer_enable === 0) {
+                $unusedTraffic = '剩余流量:0';
             } else {
-                $server = $node_custom_config['server_user'];
+                $unusedTraffic = '剩余流量:' . $user->unusedTraffic();
             }
-            switch ($node_raw->sort) {
-                case '0':
-                    $plugin = $node_custom_config['plugin'] ?? '';
-                    $plugin_option = $node_custom_config['plugin_option'] ?? '';
-
-                    $links .= $user->method . ':' . $user->passwd . '@' . $server . ':' .
-                    $user->port . '/?plugin=' . $plugin . '&' . $plugin_option . '#' .
-                    $node_raw->name . PHP_EOL;
-                    break;
+            $expire_in = '过期时间:';
+            if ($user->class_expire !== '1989-06-04 00:05:00') {
+                $userClassExpire = explode(' ', $user->class_expire);
+                $expire_in .= $userClassExpire[0];
+            } else {
+                $expire_in .= '无限期';
             }
+        } else {
+            $unusedTraffic = '账户已过期,请续费后使用';
+            $expire_in = '账户已过期,请续费后使用';
         }
-
-        return $links;
+        if (! \in_array($list, ['quantumult', 'quantumultx', 'shadowrocket'])) {
+            $info_array[] = $unusedTraffic;
+            $info_array[] = $expire_in;
+        }
+        $baseUrl = explode('//', $_ENV['baseUrl'])[1];
+        $baseUrl = explode('/', $baseUrl)[0];
+        $Extend = [
+            'remark' => '',
+            'type' => '',
+            'add' => $baseUrl,
+            'address' => $baseUrl,
+            'port' => 10086,
+            'method' => 'chacha20-ietf',
+            'passwd' => $user->passwd,
+            'id' => $user->uuid,
+            'aid' => 0,
+            'net' => 'tcp',
+            'headerType' => 'none',
+            'host' => '',
+            'path' => '/',
+            'tls' => '',
+            'protocol' => 'origin',
+            'protocol_param' => '',
+            'obfs' => 'plain',
+            'obfs_param' => '',
+            'group' => $_ENV['appName'],
+        ];
+        if ($list === 'shadowrocket') {
+            $return[] = 'STATUS=' . $unusedTraffic . '.♥.' . $expire_in . PHP_EOL . 'REMARKS=' . $_ENV['appName'];
+        }
+        foreach ($info_array as $remark) {
+            $Extend['remark'] = $remark;
+            if (\in_array($list, ['kitsunebi', 'quantumult', 'v2rayn'])) {
+                $Extend['type'] = 'vmess';
+                $out = self::getListItem($Extend, $list);
+            } elseif ($list === 'trojan') {
+                $Extend['type'] = 'trojan';
+                $out = self::getListItem($Extend, $list);
+            } elseif ($list === 'ssr') {
+                $Extend['type'] = 'ssr';
+                $out = self::getListItem($Extend, $list);
+            } else {
+                $Extend['type'] = 'ss';
+                $out = self::getListItem($Extend, $list);
+            }
+            if ($out !== null) {
+                $return[] = $out;
+            }
+        }
+        return $return;
     }
 
-    public static function getV2Ray($user): string
+    /**
+     * Surge 配置
+     *
+     * @param User  $user  用户
+     * @param int   $surge 订阅类型
+     * @param array $opts  request
+     * @param array $Rule  节点筛选规则
+     */
+    public static function getSurge(User $user, $surge, array $opts, array $Rule): string
     {
-        $links = '';
-        //篩選出用戶能連接的節點
-        $nodes_raw = Node::where('type', 1)
-            ->where('node_class', '<=', $user->class)
-            ->whereIn('node_group', [0, $user->node_group])
-            ->where(static function ($query): void {
-                $query->where('node_bandwidth_limit', '=', 0)->orWhereRaw('node_bandwidth < node_bandwidth_limit');
-            })
-            ->get();
-
-        foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
-            //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
-                $server = $node_raw->server;
-            } else {
-                $server = $node_custom_config['server_user'];
+        if ($surge !== 4) {
+            $Rule['type'] = 'ss';
+        }
+        $items = URL::getNewAllItems($user, $Rule);
+        $Nodes = [];
+        $All_Proxy = '';
+        foreach ($items as $item) {
+            $out = AppURI::getSurgeURI($item, $surge);
+            if ($out !== null) {
+                $Nodes[] = $item;
+                $All_Proxy .= $out . PHP_EOL;
             }
-            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'] ?? '/';
-                    $enable_vless = $node_custom_config['enable_vless'] ?? '0';
-
-                    $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,
-                    ];
+        }
+        $variable = ($surge === 2 ? 'Surge2_Profiles' : 'Surge_Profiles');
+        if (isset($opts['profiles']) && \in_array($opts['profiles'], array_keys($_ENV[$variable]))) {
+            $Profiles = $opts['profiles'];
+        } else {
+            $Profiles = ($surge === 2 ? $_ENV['Surge2_DefaultProfiles'] : $_ENV['Surge_DefaultProfiles']);
+        }
+        return ConfGenerate::getSurgeConfs($user, $All_Proxy, $Nodes, $_ENV[$variable][$Profiles]);
+    }
 
-                    if ($enable_vless === '1' || $enable_vless === 1) {
-                        $links .= 'vless://' . \base64_encode(\json_encode($v2rayn_array)) . PHP_EOL;
-                        break;
-                    }
-                    $links .= 'vmess://' . \base64_encode(\json_encode($v2rayn_array)) . PHP_EOL;
-                    break;
+    /**
+     * Quantumult 配置
+     *
+     * @param User  $user       用户
+     * @param int   $quantumult 订阅类型
+     * @param array $opts       request
+     * @param array $Rule       节点筛选规则
+     */
+    public static function getQuantumult(User $user, $quantumult, array $opts, array $Rule): string
+    {
+        switch ($quantumult) {
+            case 2:
+                $subUrl = self::getSubinfo($user, 0);
+                $str = [
+                    '[SERVER]',
+                    '',
+                    '[SOURCE]',
+                    $_ENV['appName'] . ', server ,' . $subUrl['ssr'] . ', false, true, false',
+                    $_ENV['appName'] . '_ss, server ,' . $subUrl['ss'] . ', false, true, false',
+                    $_ENV['appName'] . '_VMess, server ,' . $subUrl['quantumult_v2'] . ', false, true, false',
+                    'Hackl0us Rules, filter, https://raw.githubusercontent.com/Hackl0us/Surge-Rule-Snippets/master/LAZY_RULES/Quantumult.conf, true',
+                    '',
+                    '[DNS]',
+                    'system, 119.29.29.29, 223.6.6.6, 114.114.114.114',
+                    '',
+                    '[STATE]',
+                    'STATE,AUTO',
+                ];
+                return implode(PHP_EOL, $str);
+                break;
+            case 3:
+                $items = URL::getNewAllItems($user, $Rule);
+                break;
+            default:
+                return self::getLists($user, 'quantumult', $opts, $Rule);
+                break;
+        }
+
+        $All_Proxy = '';
+        $All_Proxy_name = '';
+        $BackChina_name = '';
+        foreach ($items as $item) {
+            $out = AppURI::getQuantumultURI($item);
+            if ($out !== null) {
+                $All_Proxy .= $out . PHP_EOL;
+                if (strpos($item['remark'], '回国') || strpos($item['remark'], 'China')) {
+                    $BackChina_name .= "\n" . $item['remark'];
+                } else {
+                    $All_Proxy_name .= "\n" . $item['remark'];
+                }
             }
         }
+        $ProxyGroups = [
+            'proxy_group' => base64_encode("🍃 Proxy  :  static, 🏃 Auto\n🏃 Auto\n🚀 Direct\n" . $All_Proxy_name),
+            'domestic_group' => base64_encode("🍂 Domestic  :  static, 🚀 Direct\n🚀 Direct\n🍃 Proxy\n" . $BackChina_name),
+            'others_group' => base64_encode("☁️ Others  :   static, 🍃 Proxy\n🚀 Direct\n🍃 Proxy"),
+            'direct_group' => base64_encode("🚀 Direct : static, DIRECT\nDIRECT"),
+            'apple_group' => base64_encode("🍎 Only  :  static, 🚀 Direct\n🚀 Direct\n🍃 Proxy"),
+            'auto_group' => base64_encode("🏃 Auto  :  auto\n" . $All_Proxy_name),
+        ];
+        $render = ConfRender::getTemplateRender();
+        $render->assign('All_Proxy', $All_Proxy)->assign('ProxyGroups', $ProxyGroups);
+        return $render->fetch('quantumult/quantumult.tpl');
+    }
 
-        return $links;
+    /**
+     * QuantumultX 配置
+     *
+     * @param User  $user        用户
+     * @param int   $quantumultx 订阅类型
+     * @param array $opts        request
+     * @param array $Rule        节点筛选规则
+     */
+    public static function getQuantumultX(User $user, $quantumultx, array $opts, array $Rule): string
+    {
+        return '';
     }
 
-    public static function getTrojan($user): string
+    /**
+     * Surfboard 配置
+     *
+     * @param User  $user      用户
+     * @param int   $surfboard 订阅类型
+     * @param array $opts      request
+     * @param array $Rule      节点筛选规则
+     */
+    public static function getSurfboard(User $user, int $surfboard, array $opts, array $Rule): string
     {
-        $links = '';
-        //篩選出用戶能連接的節點
-        $nodes_raw = Node::where('type', 1)
-            ->where('node_class', '<=', $user->class)
-            ->whereIn('node_group', [0, $user->node_group])
-            ->where(static function ($query): void {
-                $query->where('node_bandwidth_limit', '=', 0)->orWhereRaw('node_bandwidth < node_bandwidth_limit');
-            })
-            ->get();
-
-        foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = \json_decode($node_raw->custom_config, true);
-            //檢查是否配置“前端/订阅中下发的服务器地址”
-            if (! \array_key_exists('server_user', $node_custom_config)) {
-                $server = $node_raw->server;
-            } else {
-                $server = $node_custom_config['server_user'];
+        $Nodes = [];
+        $All_Proxy = '';
+        $items = URL::getNewAllItems($user, $Rule);
+        foreach ($items as $item) {
+            $out = AppURI::getSurfboardURI($item);
+            if ($out !== null) {
+                $Nodes[] = $item;
+                $All_Proxy .= $out . PHP_EOL;
             }
-            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 .
-                    '&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;
+        }
+        if (isset($opts['profiles']) && \in_array($opts['profiles'], array_keys($_ENV['Surfboard_Profiles']))) {
+            $Profiles = $opts['profiles'];
+        } else {
+            $Profiles = $_ENV['Surfboard_DefaultProfiles']; // 默认策略组
+        }
+
+        return ConfGenerate::getSurgeConfs($user, $All_Proxy, $Nodes, $_ENV['Surfboard_Profiles'][$Profiles]);
+    }
+
+    /**
+     * Clash 配置
+     *
+     * @param User  $user  用户
+     * @param int   $clash 订阅类型
+     * @param array $opts  request
+     * @param array $Rule  节点筛选规则
+     */
+    public static function getClash(User $user, $clash, array $opts, array $Rule): string
+    {
+        $items = URL::getNewAllItems($user, $Rule);
+        $Proxys = [];
+        foreach ($items as $item) {
+            $Proxy = AppURI::getClashURI($item);
+            if ($Proxy !== null) {
+                $Proxys[] = $Proxy;
             }
         }
+        if (isset($opts['profiles']) && \in_array($opts['profiles'], array_keys($_ENV['Clash_Profiles']))) {
+            $Profiles = $opts['profiles'];
+        } else {
+            $Profiles = $_ENV['Clash_DefaultProfiles']; // 默认策略组
+        }
+        return ConfGenerate::getClashConfs($user, $Proxys, $_ENV['Clash_Profiles'][$Profiles]);
+    }
 
-        return $links;
+    public static function getAnXray($user, $anxray, $opts, $Rule)
+    {
+        $All_Proxy = '';
+        $items = URL::getNewAllItems($user, $Rule);
+        foreach ($items as $item) {
+            $out = AppURI::getAnXrayURI($item);
+            if ($out !== null) {
+                $All_Proxy .= $out . PHP_EOL;
+            }
+        }
+        return base64_encode($All_Proxy);
+    }
+    /**
+     * 通用订阅,ssr & v2rayn
+     *
+     * @param User   $user 用户
+     * @param int    $sub  订阅类型
+     * @param array  $opts request
+     * @param array  $Rule 节点筛选规则
+     */
+    public static function getSub(User $user, $sub, array $opts, array $Rule): string
+    {
+        $return_url = '';
+        switch (((int) $sub)) {
+            case 2: // SS
+                $Rule['type'] = 'ss';
+                $getListExtend = $Rule['extend'] ? self::getListExtend($user, 'ss') : [];
+                break;
+            case 3: // V2
+                $Rule['type'] = 'vmess';
+                $getListExtend = $Rule['extend'] ? self::getListExtend($user, 'v2rayn') : [];
+                break;
+            case 4: // Trojan
+                $Rule['type'] = 'trojan';
+                $getListExtend = $Rule['extend'] ? self::getListExtend($user, 'trojan') : [];
+                break;
+            default: // SSR
+                $Rule['type'] = 'ssr';
+                $getListExtend = $Rule['extend'] ? self::getListExtend($user, 'ssr') : [];
+                break;
+        }
+        if ($Rule['extend']) {
+            $return_url .= implode(PHP_EOL, $getListExtend) . PHP_EOL;
+        }
+        $return_url .= URL::getNewAllUrl($user, $Rule);
+        return base64_encode($return_url);
     }
 
-    public static function getTraditionalSub($user)
+    /**
+     * 记录订阅日志
+     *
+     * @param User   $user 用户
+     * @param string $type 订阅类型
+     * @param string $ua   UA
+     */
+    private static function subscribeLog(User $user, string $type, string $ua): void
     {
-        $userid = $user->id;
-        $token = Link::where('userid', $userid)->first();
-        return $_ENV['subUrl'] . '/link/' . $token->token;
+        $log = new UserSubscribeLog();
+        $log->user_name = $user->user_name;
+        $log->user_id = $user->id;
+        $log->email = $user->email;
+        $log->subscribe_type = $type;
+        $log->request_ip = $_SERVER['REMOTE_ADDR'];
+        $log->request_time = date('Y-m-d H:i:s');
+        $antiXss = new AntiXSS();
+        $log->request_user_agent = $antiXss->xss_clean($ua);
+        $log->save();
     }
 }

+ 7 - 7
src/Controllers/PasswordController.php

@@ -11,7 +11,7 @@ use App\Services\Captcha;
 use App\Services\Password;
 use App\Utils\Hash;
 use App\Utils\ResponseHelper;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 /*
@@ -25,7 +25,7 @@ final class PasswordController extends BaseController
     /**
      * @param array     $args
      */
-    public function reset(Request $request, Response $response, array $args)
+    public function reset(ServerRequest $request, Response $response, array $args)
     {
         $captcha = [];
 
@@ -36,14 +36,14 @@ final class PasswordController extends BaseController
         return $response->write(
             $this->view()
                 ->assign('captcha', $captcha)
-                ->display('password/reset.tpl')
+                ->fetch('password/reset.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function handleReset(Request $request, Response $response, array $args)
+    public function handleReset(ServerRequest $request, Response $response, array $args)
     {
         if (Setting::obtain('enable_reset_password_captcha') === true) {
             $ret = Captcha::verify($request->getParams());
@@ -71,7 +71,7 @@ final class PasswordController extends BaseController
     /**
      * @param array     $args
      */
-    public function token(Request $request, Response $response, array $args)
+    public function token(ServerRequest $request, Response $response, array $args)
     {
         $token = PasswordReset::where('token', $args['token'])->where('expire_time', '>', \time())->orderBy('id', 'desc')->first();
         if ($token === null) {
@@ -79,14 +79,14 @@ final class PasswordController extends BaseController
         }
 
         return $response->write(
-            $this->view()->display('password/token.tpl')
+            $this->view()->fetch('password/token.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function handleToken(Request $request, Response $response, array $args)
+    public function handleToken(ServerRequest $request, Response $response, array $args)
     {
         $tokenStr = $args['token'];
         $password = $request->getParam('password');

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

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\DetectLog;
 use App\Models\DetectRule;
 use App\Utils\Tools;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class DetectController extends BaseController
@@ -16,7 +16,7 @@ final class DetectController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function detectIndex(ServerRequest $request, Response $response, array $args)
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $logs = DetectRule::paginate(15, ['*'], 'page', $pageNum);
@@ -29,16 +29,16 @@ final class DetectController extends BaseController
         }
 
         $render = Tools::paginateRender($logs);
-        return $this->view()
+        return $response->write($this->view()
             ->assign('rules', $logs)
             ->assign('render', $render)
-            ->display('user/detect/index.tpl');
+            ->fetch('user/detect_index.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function log(Request $request, Response $response, array $args)
+    public function detectLog(ServerRequest $request, Response $response, array $args)
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $logs = DetectLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->paginate(15, ['*'], 'page', $pageNum);
@@ -68,9 +68,9 @@ final class DetectController extends BaseController
         }
 
         $render = Tools::paginateRender($logs);
-        return $this->view()
+        return $response->write($this->view()
             ->assign('logs', $logs)
             ->assign('render', $render)
-            ->display('user/detect/log.tpl');
+            ->fetch('user/detect_log.tpl'));
     }
 }

+ 3 - 3
src/Controllers/User/ServerController.php

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\Node;
 use App\Utils\Tools;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 /**
@@ -19,7 +19,7 @@ final class ServerController extends BaseController
     /**
      * @param array     $args
      */
-    public function userServerPage(Request $request, Response $response, array $args): ResponseInterface
+    public function userServerPage(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $query = Node::query();
@@ -51,7 +51,7 @@ final class ServerController extends BaseController
         return $response->write(
             $this->view()
                 ->assign('servers', $all_node)
-                ->display('user/server.tpl')
+                ->fetch('user/server.tpl')
         );
     }
 }

+ 6 - 6
src/Controllers/User/ShopController.php

@@ -11,7 +11,7 @@ use App\Models\Payback;
 use App\Models\Setting;
 use App\Models\Shop;
 use App\Utils\ResponseHelper;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class ShopController extends BaseController
@@ -19,16 +19,16 @@ final class ShopController extends BaseController
     /**
      * @param array     $args
      */
-    public function shop(Request $request, Response $response, array $args)
+    public function shop(ServerRequest $request, Response $response, array $args)
     {
         $shops = Shop::where('status', 1)->orderBy('name')->get();
-        return $this->view()->assign('shops', $shops)->display('user/shop.tpl');
+        return $response->write($this->view()->assign('shops', $shops)->fetch('user/shop.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function couponCheck(Request $request, Response $response, array $args)
+    public function couponCheck(ServerRequest $request, Response $response, array $args)
     {
         $coupon = $request->getParam('coupon');
         $coupon = trim($coupon);
@@ -80,7 +80,7 @@ final class ShopController extends BaseController
     /**
      * @param array     $args
      */
-    public function buy(Request $request, Response $response, array $args)
+    public function buy(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $shop = $request->getParam('shop');
@@ -170,7 +170,7 @@ final class ShopController extends BaseController
     /**
      * @param array     $args
      */
-    public function buyTrafficPackage(Request $request, Response $response, array $args)
+    public function buyTrafficPackage(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $shop = $request->getParam('shop');

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

@@ -9,7 +9,7 @@ use App\Models\Ticket;
 use App\Models\User;
 use App\Utils\Tools;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 use voku\helper\AntiXSS;
 
@@ -21,7 +21,7 @@ final class TicketController extends BaseController
     /**
      * @param array     $args
      */
-    public function ticket(Request $request, Response $response, array $args): ?ResponseInterface
+    public function ticket(ServerRequest $request, Response $response, array $args): ?ResponseInterface
     {
         if ($_ENV['enable_ticket'] !== true) {
             return null;
@@ -45,14 +45,14 @@ final class TicketController extends BaseController
         return $response->write(
             $this->view()
                 ->assign('tickets', $tickets)
-                ->display('user/ticket/index.tpl')
+                ->fetch('user/ticket/index.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function ticketAdd(Request $request, Response $response, array $args): ResponseInterface
+    public function ticketAdd(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $title = $request->getParam('title');
         $comment = $request->getParam('comment');
@@ -123,7 +123,7 @@ final class TicketController extends BaseController
     /**
      * @param array     $args
      */
-    public function ticketUpdate(Request $request, Response $response, array $args): ResponseInterface
+    public function ticketUpdate(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $comment = $request->getParam('comment');
@@ -196,7 +196,7 @@ final class TicketController extends BaseController
     /**
      * @param array     $args
      */
-    public function ticketView(Request $request, Response $response, array $args): ResponseInterface
+    public function ticketView(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->where('userid', $this->user->id)->first();
@@ -226,7 +226,7 @@ final class TicketController extends BaseController
                 ->assign('ticket', $ticket)
                 ->assign('comments', $comments)
                 ->registerClass('Tools', Tools::class)
-                ->display('user/ticket/view.tpl')
+                ->fetch('user/ticket/view.tpl')
         );
     }
 }

+ 198 - 95
src/Controllers/UserController.php

@@ -16,6 +16,7 @@ use App\Models\Node;
 use App\Models\Payback;
 use App\Models\Setting;
 use App\Models\StreamMedia;
+use App\Models\Token;
 use App\Models\User;
 use App\Models\UserSubscribeLog;
 use App\Services\Auth;
@@ -31,8 +32,9 @@ use App\Utils\QQWry;
 use App\Utils\ResponseHelper;
 use App\Utils\TelegramSessionManager;
 use App\Utils\Tools;
+use App\Utils\URL;
 use Ramsey\Uuid\Uuid;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 use voku\helper\AntiXSS;
 
@@ -44,7 +46,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function index(Request $request, Response $response, array $args)
+    public function index(ServerRequest $request, Response $response, array $args)
     {
         $captcha = [];
 
@@ -52,6 +54,24 @@ final class UserController extends BaseController
             $captcha = Captcha::generate();
         }
 
+        if ($_ENV['subscribe_client_url'] !== '') {
+            $getClient = new Token();
+            for ($i = 0; $i < 10; $i++) {
+                $token = $this->user->id . Tools::genRandomChar(16);
+                $Elink = Token::where('token', '=', $token)->first();
+                if ($Elink === null) {
+                    $getClient->token = $token;
+                    break;
+                }
+            }
+            $getClient->user_id = $this->user->id;
+            $getClient->create_time = \time();
+            $getClient->expire_time = \time() + 10 * 60;
+            $getClient->save();
+        } else {
+            $token = '';
+        }
+
         $data = [
             'today_traffic_usage' => (int) $this->user->transfer_enable === 0 ? 0 : ($this->user->u + $this->user->d - $this->user->last_day_t) / $this->user->transfer_enable * 100,
             'past_traffic_usage' => (int) $this->user->transfer_enable === 0 ? 0 : $this->user->last_day_t / $this->user->transfer_enable * 100,
@@ -60,19 +80,24 @@ final class UserController extends BaseController
 
         return $response->write(
             $this->view()
+                ->assign('ssr_sub_token', $this->user->getSublink())
                 ->assign('ann', Ann::orderBy('date', 'desc')->first())
+                ->assign('mergeSub', $_ENV['mergeSub'])
+                ->assign('subUrl', $_ENV['subUrl'] . '/link/')
+                ->registerClass('URL', URL::class)
+                ->assign('subInfo', LinkController::getSubinfo($this->user, 0))
                 ->assign('getUniversalSub', SubController::getUniversalSub($this->user))
-                ->assign('getTraditionalSub', LinkController::getTraditionalSub($this->user))
+                ->assign('getClient', $token)
                 ->assign('data', $data)
                 ->assign('captcha', $captcha)
-                ->display('user/index.tpl')
+                ->fetch('user/index.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function code(Request $request, Response $response, array $args)
+    public function code(ServerRequest $request, Response $response, array $args)
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $codes = Code::where('type', '<>', '-2')
@@ -87,14 +112,14 @@ final class UserController extends BaseController
                 ->assign('codes', $codes)
                 ->assign('payments', Payment::getPaymentsEnabled())
                 ->assign('render', $render)
-                ->display('user/code.tpl')
+                ->fetch('user/code.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function codeCheck(Request $request, Response $response, array $args)
+    public function codeCheck(ServerRequest $request, Response $response, array $args)
     {
         $time = $request->getQueryParams()['time'];
         $codes = Code::where('userid', '=', $this->user->id)
@@ -114,7 +139,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function codePost(Request $request, Response $response, array $args)
+    public function codePost(ServerRequest $request, Response $response, array $args)
     {
         $code = trim($request->getParam('code'));
         if ($code === '') {
@@ -154,9 +179,9 @@ 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);
+                $user->expire_in = date('Y-m-d H:i:s', \time() + $codeq->number * 86400);
             } else {
-                $user->expire_in = date('Y-m-d H:i:s', strtotime($user->expire_in) + (int) $codeq->number * 86400);
+                $user->expire_in = date('Y-m-d H:i:s', strtotime($user->expire_in) + $codeq->number * 86400);
             }
             $user->save();
         }
@@ -166,7 +191,7 @@ final class UserController extends BaseController
                 $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);
+            $user->class_expire = date('Y-m-d H:i:s', strtotime($user->class_expire) + $codeq->number * 86400);
             $user->class = $codeq->type;
             $user->save();
         }
@@ -180,7 +205,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function checkGa(Request $request, Response $response, array $args)
+    public function checkGa(ServerRequest $request, Response $response, array $args)
     {
         $code = $request->getParam('code');
         if ($code === '') {
@@ -207,7 +232,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function setGa(Request $request, Response $response, array $args)
+    public function setGa(ServerRequest $request, Response $response, array $args)
     {
         $enable = $request->getParam('enable');
         if ($enable === '') {
@@ -228,7 +253,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetPort(Request $request, Response $response, array $args)
+    public function resetPort(ServerRequest $request, Response $response, array $args)
     {
         $temp = $this->user->resetPort();
         return $response->withJson([
@@ -240,7 +265,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function specifyPort(Request $request, Response $response, array $args)
+    public function specifyPort(ServerRequest $request, Response $response, array $args)
     {
         $temp = $this->user->specifyPort((int) $request->getParam('port'));
         return $response->withJson([
@@ -252,7 +277,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetGa(Request $request, Response $response, array $args)
+    public function resetGa(ServerRequest $request, Response $response, array $args)
     {
         $ga = new GA();
         $secret = $ga->createSecret();
@@ -265,7 +290,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function profile(Request $request, Response $response, array $args)
+    public function profile(ServerRequest $request, Response $response, array $args)
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $paybacks = Payback::where('ref_by', $this->user->id)
@@ -309,14 +334,14 @@ final class UserController extends BaseController
                 ->assign('userloginip', $totallogin)
                 ->assign('paybacks', $paybacks)
                 ->registerClass('Tools', Tools::class)
-                ->display('user/profile.tpl')
+                ->fetch('user/profile.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function announcement(Request $request, Response $response, array $args)
+    public function announcement(ServerRequest $request, Response $response, array $args)
     {
         $Anns = Ann::orderBy('date', 'desc')->get();
 
@@ -330,14 +355,14 @@ final class UserController extends BaseController
         return $response->write(
             $this->view()
                 ->assign('anns', $Anns)
-                ->display('user/announcement.tpl')
+                ->fetch('user/announcement.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function docs(Request $request, Response $response, array $args)
+    public function docs(ServerRequest $request, Response $response, array $args)
     {
         $docs = Docs::orderBy('id', 'desc')->get();
 
@@ -351,14 +376,14 @@ final class UserController extends BaseController
         return $response->write(
             $this->view()
                 ->assign('docs', $docs)
-                ->display('user/docs.tpl')
+                ->fetch('user/docs.tpl')
         );
     }
 
     /**
      * @param array     $args
      */
-    public function media(Request $request, Response $response, array $args)
+    public function media(ServerRequest $request, Response $response, array $args)
     {
         $results = [];
         $db = new DatatablesHelper();
@@ -413,37 +438,37 @@ final class UserController extends BaseController
             }
         }
 
-        $node_names = array_column($results, 'node_name');
-        array_multisort($node_names, SORT_ASC, $results);
+        array_multisort(array_column($results, 'node_name'), SORT_ASC, $results);
 
-        return $this->view()
+        return $response->write($this->view()
             ->assign('results', $results)
-            ->display('user/media.tpl');
+            ->fetch('user/media.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function edit(Request $request, Response $response, array $args)
+    public function edit(ServerRequest $request, Response $response, array $args)
     {
         $themes = Tools::getDir(BASE_PATH . '/resources/views');
         $bind_token = TelegramSessionManager::addBindSession($this->user);
         $methods = Config::getSupportParam('method');
 
-        return $this->view()
+        return $reponse->write($this->view()
             ->assign('user', $this->user)
             ->assign('themes', $themes)
             ->assign('bind_token', $bind_token)
             ->assign('methods', $methods)
             ->assign('telegram_bot', $_ENV['telegram_bot'])
             ->registerClass('Config', Config::class)
-            ->display('user/edit.tpl');
+            ->registerClass('URL', URL::class)
+            ->fetch('user/edit.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function invite(Request $request, Response $response, array $args)
+    public function invite(ServerRequest $request, Response $response, array $args)
     {
         $code = InviteCode::where('user_id', $this->user->id)->first();
         if ($code === null) {
@@ -466,19 +491,19 @@ final class UserController extends BaseController
 
         $invite_url = $_ENV['baseUrl'] . '/auth/register?code=' . $code->code;
 
-        return $this->view()
+        return $response->write($this->view()
             ->assign('code', $code)
             ->assign('render', $render)
             ->assign('paybacks', $paybacks)
             ->assign('invite_url', $invite_url)
             ->assign('paybacks_sum', $paybacks_sum)
-            ->display('user/invite.tpl');
+            ->fetch('user/invite.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function buyInvite(Request $request, Response $response, array $args)
+    public function buyInvite(ServerRequest $request, Response $response, array $args)
     {
         $price = Setting::obtain('invite_price');
         $num = $request->getParam('num');
@@ -509,7 +534,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function customInvite(Request $request, Response $response, array $args)
+    public function customInvite(ServerRequest $request, Response $response, array $args)
     {
         $price = Setting::obtain('custom_invite_price');
         $customcode = $request->getParam('customcode');
@@ -549,7 +574,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function updatePassword(Request $request, Response $response, array $args)
+    public function updatePassword(ServerRequest $request, Response $response, array $args)
     {
         $oldpwd = $request->getParam('oldpwd');
         $pwd = $request->getParam('pwd');
@@ -579,7 +604,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function updateEmail(Request $request, Response $response, array $args)
+    public function updateEmail(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $newemail = $request->getParam('newemail');
@@ -625,7 +650,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function updateUsername(Request $request, Response $response, array $args)
+    public function updateUsername(ServerRequest $request, Response $response, array $args)
     {
         $newusername = $request->getParam('newusername');
         $user = $this->user;
@@ -639,7 +664,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function bought(Request $request, Response $response, array $args)
+    public function bought(ServerRequest $request, Response $response, array $args)
     {
         $pageNum = $request->getQueryParams()['page'] ?? 1;
         $shops = Bought::where('userid', $this->user->id)->orderBy('id', 'desc')->paginate(15, ['*'], 'page', $pageNum);
@@ -655,16 +680,16 @@ final class UserController extends BaseController
             ]);
         }
         $render = Tools::paginateRender($shops);
-        return $this->view()
+        return $response->write($this->view()
             ->assign('shops', $shops)
             ->assign('render', $render)
-            ->display('user/bought.tpl');
+            ->fetch('user/bought.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function deleteBoughtGet(Request $request, Response $response, array $args)
+    public function deleteBoughtGet(ServerRequest $request, Response $response, array $args)
     {
         $id = $request->getParam('id');
         $shop = Bought::where('id', $id)->where('userid', $this->user->id)->first();
@@ -686,77 +711,126 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function updateContact(Request $request, Response $response, array $args)
+    public function updateContact(ServerRequest $request, Response $response, array $args)
     {
-        $antiXss = new AntiXSS();
-
-        $type = $antiXss->xss_clean($request->getParam('imtype'));
-        $value = $antiXss->xss_clean($request->getParam('imvalue'));
+        $type = $request->getParam('imtype');
+        $contact = trim($request->getParam('contact'));
 
         $user = $this->user;
 
         if ($user->telegram_id !== null) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '你的账户绑定了 Telegram ,所以此项并不能被修改',
-            ]);
+            return ResponseHelper::error(
+                $response,
+                '绑定了 Telegram ,所以此项并不能被修改'
+            );
         }
 
-        if ($value === '' || $type === '') {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '联络方式不能为空',
-            ]);
+        if ($contact === '' || $type === '') {
+            return ResponseHelper::error($response, '非法输入');
         }
 
-        $user_exist = User::where('im_value', $value)->where('im_type', $type)->first();
-        if ($user_exist !== null) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '此联络方式已经被注册',
-            ]);
+        $user1 = User::where('im_value', $contact)->where('im_type', $type)->first();
+        if ($user1 !== null) {
+            return ResponseHelper::error($response, '此联络方式已经被注册');
         }
 
         $user->im_type = $type;
-        $user->im_value = $value;
+        $antiXss = new AntiXSS();
+        $user->im_value = $antiXss->xss_clean($contact);
         $user->save();
 
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '修改成功',
-        ]);
+        return ResponseHelper::successfully($response, '修改成功');
     }
 
     /**
      * @param array     $args
      */
-    public function updateTheme(Request $request, Response $response, array $args)
+    public function updateSSR(ServerRequest $request, Response $response, array $args)
     {
+        $protocol = $request->getParam('protocol');
+        $obfs = $request->getParam('obfs');
+        $obfs_param = $request->getParam('obfs_param');
+        $obfs_param = trim($obfs_param);
+
+        $user = $this->user;
+
+        if ($obfs === '' || $protocol === '') {
+            return ResponseHelper::error($response, '非法输入');
+        }
+
+        if (! Tools::isParamValidate('obfs', $obfs)) {
+            return ResponseHelper::error($response, '协议无效');
+        }
+
+        if (! Tools::isParamValidate('protocol', $protocol)) {
+            return ResponseHelper::error($response, '协议无效');
+        }
+
         $antiXss = new AntiXSS();
-        $theme = $antiXss->xss_clean($request->getParam('theme'));
+
+        $user->protocol = $antiXss->xss_clean($protocol);
+        $user->obfs = $antiXss->xss_clean($obfs);
+        $user->obfs_param = $antiXss->xss_clean($obfs_param);
+
+        if (! Tools::checkNoneProtocol($user)) {
+            return ResponseHelper::error(
+                $response,
+                '系统检测到您目前的加密方式为 none ,但您将要设置为的协议并不在以下协议<br>'
+                . implode(',', Config::getSupportParam('allow_none_protocol'))
+                . '<br>之内,请您先修改您的加密方式,再来修改此处设置。'
+            );
+        }
+
+        if (! URL::SSCanConnect($user) && ! URL::SSRCanConnect($user)) {
+            return ResponseHelper::error(
+                $response,
+                '您这样设置之后,就没有客户端能连接上了,所以系统拒绝了您的设置,请您检查您的设置之后再进行操作。'
+            );
+        }
+
+        $user->save();
+
+        if (! URL::SSCanConnect($user)) {
+            return ResponseHelper::error(
+                $response,
+                '设置成功,但您目前的协议,混淆,加密方式设置会导致 Shadowsocks原版客户端无法连接,请您自行更换到 ShadowsocksR 客户端。'
+            );
+        }
+
+        if (! URL::SSRCanConnect($user)) {
+            return ResponseHelper::error(
+                $response,
+                '设置成功,但您目前的协议,混淆,加密方式设置会导致 ShadowsocksR 客户端无法连接,请您自行更换到 Shadowsocks 客户端。'
+            );
+        }
+
+        return ResponseHelper::successfully($response, '设置成功,您可自由选用客户端来连接。');
+    }
+
+    /**
+     * @param array     $args
+     */
+    public function updateTheme(ServerRequest $request, Response $response, array $args)
+    {
+        $theme = $request->getParam('theme');
 
         $user = $this->user;
 
         if ($theme === '') {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '主题不能为空',
-            ]);
+            return ResponseHelper::error($response, '非法输入');
         }
 
-        $user->theme = $theme;
+        $antiXss = new AntiXSS();
+        $user->theme = $antiXss->xss_clean($theme);
         $user->save();
 
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '修改成功',
-        ]);
+        return ResponseHelper::successfully($response, '设置成功');
     }
 
     /**
      * @param array     $args
      */
-    public function updateMail(Request $request, Response $response, array $args)
+    public function updateMail(ServerRequest $request, Response $response, array $args)
     {
         $value = (int) $request->getParam('mail');
         if (\in_array($value, [0, 1, 2])) {
@@ -777,7 +851,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetPasswd(Request $request, Response $response, array $args)
+    public function resetPasswd(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $pwd = Tools::genRandomChar(16);
@@ -799,7 +873,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function updateMethod(Request $request, Response $response, array $args)
+    public function updateMethod(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
 
@@ -823,7 +897,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function logout(Request $request, Response $response, array $args)
+    public function logout(ServerRequest $request, Response $response, array $args)
     {
         Auth::logout();
         return $response->withStatus(302)->withHeader('Location', '/');
@@ -832,7 +906,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function doCheckIn(Request $request, Response $response, array $args)
+    public function doCheckIn(ServerRequest $request, Response $response, array $args)
     {
         if ($_ENV['enable_checkin'] === false) {
             return ResponseHelper::error($response, '暂时还不能签到');
@@ -870,15 +944,15 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function kill(Request $request, Response $response, array $args)
+    public function kill(ServerRequest $request, Response $response, array $args)
     {
-        return $this->view()->display('user/kill.tpl');
+        return $response->write($this->view()->fetch('user/kill.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function handleKill(Request $request, Response $response, array $args)
+    public function handleKill(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
 
@@ -898,18 +972,18 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function banned(Request $request, Response $response, array $args)
+    public function banned(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
-        return $this->view()
+        return $response->write($this->view()
             ->assign('banned_reason', $user->banned_reason)
-            ->display('user/banned.tpl');
+            ->fetch('user/banned.tpl'));
     }
 
     /**
      * @param array     $args
      */
-    public function resetTelegram(Request $request, Response $response, array $args)
+    public function resetTelegram(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $user->telegramReset();
@@ -920,7 +994,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetURL(Request $request, Response $response, array $args)
+    public function resetURL(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $user->cleanLink();
@@ -931,7 +1005,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function resetInviteURL(Request $request, Response $response, array $args)
+    public function resetInviteURL(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         $user->clearInviteCodes();
@@ -942,7 +1016,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function backtoadmin(Request $request, Response $response, array $args)
+    public function backtoadmin(ServerRequest $request, Response $response, array $args)
     {
         $userid = Cookie::get('uid');
         $adminid = Cookie::get('old_uid');
@@ -982,12 +1056,41 @@ final class UserController extends BaseController
         return $response->withStatus(302)->withHeader('Location', $local);
     }
 
+    /**
+     * @param array     $args
+     */
+    public function getUserAllURL(ServerRequest $request, Response $response, array $args)
+    {
+        $user = $this->user;
+        $type = $request->getQueryParams()['type'];
+        $return = '';
+        switch ($type) {
+            case 'ss':
+                $return .= URL::getNewAllUrl($user, ['type' => 'ss']) . PHP_EOL;
+                break;
+            case 'ssr':
+                $return .= URL::getNewAllUrl($user, ['type' => 'ssr']) . PHP_EOL;
+                break;
+            case 'v2ray':
+                $return .= URL::getNewAllUrl($user, ['type' => 'vmess']) . PHP_EOL;
+                break;
+            default:
+                $return .= '悟空别闹!';
+                break;
+        }
+        $response = $response->withHeader('Content-type', ' application/octet-stream; charset=utf-8')
+            ->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate')
+            ->withHeader('Content-Disposition', ' attachment; filename=node.txt');
+
+        return $response->write($return);
+    }
+
     /**
      * 订阅记录
      *
      * @param array    $args
      */
-    public function subscribeLog(Request $request, Response $response, array $args)
+    public function subscribeLog(ServerRequest $request, Response $response, array $args)
     {
         if ($_ENV['subscribeLog_show'] === false) {
             return $response->withStatus(302)->withHeader('Location', '/user');
@@ -1007,7 +1110,7 @@ final class UserController extends BaseController
     /**
      * @param array     $args
      */
-    public function switchThemeMode(Request $request, Response $response, array $args)
+    public function switchThemeMode(ServerRequest $request, Response $response, array $args)
     {
         $user = $this->user;
         if ($user->is_dark_mode === 1) {

+ 14 - 12
src/Controllers/WebAPI/FuncController.php

@@ -2,13 +2,13 @@
 
 declare(strict_types=1);
 
-namespace App\Controllers\WebAPI;
+namespace App\Controllers\Node;
 
 use App\Controllers\BaseController;
 use App\Models\DetectRule;
 use App\Utils\ResponseHelper;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class FuncController extends BaseController
@@ -16,18 +16,19 @@ final class FuncController extends BaseController
     /**
      * @param array     $args
      */
-    public function ping(Request $request, Response $response, array $args): ResponseInterface
+    public function ping(ServerRequest $request, Response $response, array $args)
     {
-        return $response->withJson([
+        $res = [
             'ret' => 1,
-            'data' => 'Pong? Pong!',
-        ]);
+            'data' => 'pong',
+        ];
+        return $response->withJson($res);
     }
 
     /**
      * @param array     $args
      */
-    public function getDetectLogs(Request $request, Response $response, array $args): ResponseInterface
+    public function getDetectLogs(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $rules = DetectRule::all();
 
@@ -41,7 +42,7 @@ final class FuncController extends BaseController
     /**
      * @param array     $args
      */
-    public function getBlockip(Request $request, Response $response, array $args): ResponseInterface
+    public function getBlockip(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return ResponseHelper::etagJson($request, $response, [
             'ret' => 1,
@@ -52,7 +53,7 @@ final class FuncController extends BaseController
     /**
      * @param array     $args
      */
-    public function getUnblockip(Request $request, Response $response, array $args): ResponseInterface
+    public function getUnblockip(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         return ResponseHelper::etagJson($request, $response, [
             'ret' => 1,
@@ -63,11 +64,12 @@ final class FuncController extends BaseController
     /**
      * @param array     $args
      */
-    public function addBlockIp(Request $request, Response $response, array $args): ResponseInterface
+    public function addBlockIp(ServerRequest $request, Response $response, array $args)
     {
-        return $response->withJson([
+        $res = [
             'ret' => 1,
             'data' => 'ok',
-        ]);
+        ];
+        return $response->withJson($res);
     }
 }

+ 22 - 15
src/Controllers/WebAPI/NodeController.php

@@ -2,14 +2,14 @@
 
 declare(strict_types=1);
 
-namespace App\Controllers\WebAPI;
+namespace App\Controllers\Node;
 
 use App\Controllers\BaseController;
 use App\Models\Node;
 use App\Models\StreamMedia;
 use App\Utils\ResponseHelper;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class NodeController extends BaseController
@@ -17,7 +17,7 @@ final class NodeController extends BaseController
     /**
      * @param array     $args
      */
-    public function saveReport(Request $request, Response $response, array $args): ResponseInterface
+    public function saveReport(ServerRequest $request, Response $response, array $args): void
     {
         $node_id = $request->getParam('node_id');
         $content = $request->getParam('content');
@@ -27,28 +27,25 @@ final class NodeController extends BaseController
         $report->result = \json_encode($result);
         $report->created_at = \time();
         $report->save();
-
-        return $response->withJson([
-            'ret' => 1,
-            'data' => 'ok',
-        ]);
+        die('ok');
     }
 
     /**
      * @param array     $args
      */
-    public function info(Request $request, Response $response, array $args): ResponseInterface
+    public function info(ServerRequest $request, Response $response, array $args)
     {
-        return $response->withJson([
+        $res = [
             'ret' => 1,
             'data' => 'ok',
-        ]);
+        ];
+        return $response->withJson($res);
     }
 
     /**
      * @param array     $args
      */
-    public function getInfo(Request $request, Response $response, array $args): ResponseInterface
+    public function getInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $node_id = $args['id'];
         $node = Node::find($node_id);
@@ -86,11 +83,21 @@ final class NodeController extends BaseController
     /**
      * @param array     $args
      */
-    public function getAllInfo(Request $request, Response $response, array $args): ResponseInterface
+    public function getAllInfo(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        return $response->withJson([
+        $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, [
             'ret' => 1,
-            'data' => [],
+            'data' => $nodes,
         ]);
     }
 }

+ 5 - 5
src/Controllers/WebAPI/UserController.php

@@ -14,7 +14,7 @@ use App\Utils\ResponseHelper;
 use App\Utils\Tools;
 use Illuminate\Database\Eloquent\Builder;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class UserController extends BaseController
@@ -22,7 +22,7 @@ final class UserController extends BaseController
     /**
      * GET /mod_mu/users
      *
-     * @param Request   $request
+     * @param ServerRequest   $request
      * @param Response  $response
      * @param array     $args
      *
@@ -95,7 +95,7 @@ final class UserController extends BaseController
     /**
      * POST /mod_mu/users/traffic
      *
-     * @param Request   $request
+     * @param ServerRequest   $request
      * @param Response  $response
      * @param array     $args
      *
@@ -149,7 +149,7 @@ final class UserController extends BaseController
     /**
      * POST /mod_mu/users/aliveip
      *
-     * @param Request   $request
+     * @param ServerRequest   $request
      * @param Response  $response
      * @param array     $args
      *
@@ -194,7 +194,7 @@ final class UserController extends BaseController
     /**
      * POST /mod_mu/users/detectlog
      *
-     * @param Request   $request
+     * @param ServerRequest   $request
      * @param Response  $response
      * @param array     $args
      *

+ 12 - 7
src/Middleware/Admin.php

@@ -5,18 +5,23 @@ declare(strict_types=1);
 namespace App\Middleware;
 
 use App\Services\Auth as AuthService;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\Factory\AppFactory;
 
-final class Admin
+final class Admin implements MiddlewareInterface
 {
-    public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next): \Slim\Http\Response
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         $user = AuthService::getUser();
-        if (! $user->isLogin) {
-            return $response->withStatus(302)->withHeader('Location', '/auth/login');
+        if (!$user->isLogin) {
+            return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/auth/login');
         }
-        if (! $user->is_admin) {
-            return $response->withStatus(302)->withHeader('Location', '/user');
+        if (!$user->is_admin) {
+            return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/user');
         }
-        return $next($request, $response);
+        return $handler->handle($request);
     }
 }

+ 18 - 7
src/Middleware/Auth.php

@@ -5,19 +5,30 @@ declare(strict_types=1);
 namespace App\Middleware;
 
 use App\Services\Auth as AuthService;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\Factory\AppFactory;
 
-final class Auth
+use function in_array;
+
+final class Auth implements MiddlewareInterface
 {
-    public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next): \Slim\Http\Response
+    /**
+     * @inheritdoc
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         $user = AuthService::getUser();
-        if (! $user->isLogin) {
-            return $response->withStatus(302)->withHeader('Location', '/auth/login');
+        if (!$user->isLogin) {
+            return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/auth/login');
         }
         $enablePages = ['/user/banned', '/user/backtoadmin', '/user/logout'];
-        if ($user->is_banned === 1 && ! \in_array($_SERVER['REQUEST_URI'], $enablePages)) {
-            return $response->withStatus(302)->withHeader('Location', '/user/banned');
+        if ($user->is_banned === 1 && !in_array($request->getUri()->getPath(), $enablePages)) {
+            return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/user/banned');
         }
-        return $next($request, $response);
+        $request = $request->withAttribute('user', $user);
+        return $handler->handle($request);
     }
 }

+ 23 - 21
src/Middleware/AuthorizationBearer.php

@@ -4,7 +4,15 @@ declare(strict_types=1);
 
 namespace App\Middleware;
 
-final class AuthorizationBearer
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\Factory\AppFactory;
+
+use function substr;
+
+final class AuthorizationBearer implements MiddlewareInterface
 {
     private string $token;
 
@@ -13,34 +21,28 @@ final class AuthorizationBearer
         $this->token = $token;
     }
 
-    public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next): \Slim\Http\Response
+    /**
+     * @inheritdoc
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
-        if (! $request->hasHeader('Authorization')) {
-            return $response->withStatus(401)->withJson([
-                'ret' => 0,
-                'data' => 'Authorization failed',
-            ]);
-        }
+        // The OAuth 2.0 Authorization Framework: Bearer Token Usage
+        // https://www.rfc-editor.org/rfc/rfc6750
 
         $authHeader = $request->getHeaderLine('Authorization');
 
-        // Bearer method token verify
-        if (strtoupper(substr($authHeader, 0, 6)) !== 'BEARER') {
-            return $response->withStatus(401)->withJson([
-                'ret' => 0,
-                'data' => 'Authorization failed',
-            ]);
-        }
-
-        $realToken = substr($authHeader, 7);
-
-        if ($realToken !== $this->token) {
-            return $response->withStatus(401)->withJson([
+        if (
+            substr($authHeader, 0, 7) !== 'Bearer ' ||
+            substr($authHeader, 8) !== $this->token
+        ) {
+            /** @var \Slim\Http\Response */
+            $response = AppFactory::determineResponseFactory()->createResponse(401);
+            return $response->withJson([
                 'ret' => 0,
                 'data' => 'Authorization failed',
             ]);
         }
 
-        return $next($request, $response);
+        return $handler->handle($request);
     }
 }

+ 48 - 0
src/Middleware/ErrorHandler.php

@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Middleware;
+
+use App\Services\View;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\CallableResolver;
+use Slim\Exception\HttpMethodNotAllowedException;
+use Slim\Exception\HttpNotFoundException;
+use Slim\Factory\AppFactory;
+use Slim\Handlers\ErrorHandler as SlimErrorHandler;
+use Throwable;
+
+final class ErrorHandler implements MiddlewareInterface
+{
+    /**
+     * @inheritdoc
+     */
+    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->getBody()->write($smarty->fetch("$code.tpl"));
+            $response = $response->withStatus($code);
+        } catch (Throwable $e) {
+            $response_factory = AppFactory::determineResponseFactory();
+            if ($_ENV['debug'] ?? false === true) {
+                $callable_resolver = new CallableResolver(null);
+                $error_handler = new SlimErrorHandler($callable_resolver, $response_factory);
+                $response = $error_handler($request, $e, true, true, false);
+            } else {
+                $response = $response_factory->createResponse(500);
+                $smarty = View::getSmarty();
+                $response->getBody()->write($smarty->fetch("500.tpl"));
+            }
+        }
+        return $response;
+    }
+}

+ 13 - 4
src/Middleware/Guest.php

@@ -5,15 +5,24 @@ declare(strict_types=1);
 namespace App\Middleware;
 
 use App\Services\Auth as AuthService;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\Factory\AppFactory;
 
-final class Guest
+final class Guest implements MiddlewareInterface
 {
-    public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next): \Slim\Http\Response
+    /**
+     * @inheritdoc
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         $user = AuthService::getUser();
         if ($user->isLogin) {
-            return $response->withStatus(302)->withHeader('Location', '/user');
+            $response = AppFactory::determineResponseFactory()->createResponse(302);
+            return $response->withHeader('Location', '/user');
         }
-        return $next($request, $response);
+        return $handler->handle($request);
     }
 }

+ 7 - 12
src/Middleware/NodeToken.php

@@ -6,23 +6,18 @@ namespace App\Middleware;
 
 use App\Models\Node;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
-use Slim\Http\Response;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
 
-final class NodeToken
+final class NodeToken implements MiddlewareInterface
 {
     /**
-     * MID /mod_mu/
-     *
-     * @param Request $request
-     * @param Response $response
-     * @param callable $next
-     *
-     * @return ResponseInterface
+     * @inheritdoc
      */
-    public function __invoke($request, $response, $next)
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
-        $key = $request->getQueryParam('key');
+        $key = $request->getQueryParams()['key'] ?? null;
         if ($key === null) {
             // 未提供 key
             return $response->withJson([

+ 1 - 1
src/Models/Model.php

@@ -31,7 +31,7 @@ abstract class Model extends EloquentModel
      *  'count' => int
      * ]
      */
-    public static function getTableDataFromAdmin(\Slim\Http\Request $request, ?callable $callback = null, ?callable $precondition = null): array
+    public static function getTableDataFromAdmin(\Slim\Http\ServerRequest $request, ?callable $callback = null, ?callable $precondition = null): array
     {
         //得到排序的方式
         $order = $request->getParam('order')[0]['dir'];

+ 1 - 1
src/Services/Gateway/AbstractPayment.php

@@ -11,7 +11,7 @@ use App\Models\Setting;
 use App\Models\User;
 use Psr\Http\Message\ResponseInterface;
 use Ramsey\Uuid\Uuid;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 abstract class AbstractPayment

+ 1 - 1
src/Services/Gateway/AopF2F.php

@@ -13,7 +13,7 @@ use Omnipay\Alipay\AbstractAopGateway;
 use Omnipay\Alipay\AopF2FGateway;
 use Omnipay\Omnipay;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class AopF2F extends AbstractPayment

+ 1 - 1
src/Services/Gateway/Epay.php

@@ -17,7 +17,7 @@ use App\Services\Gateway\Epay\EpayNotify;
 use App\Services\Gateway\Epay\EpaySubmit;
 use App\Services\View;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class Epay extends AbstractPayment

+ 1 - 1
src/Services/Gateway/PAYJS.php

@@ -9,7 +9,7 @@ use App\Models\Setting;
 use App\Services\Auth;
 use App\Services\View;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class PAYJS extends AbstractPayment

+ 1 - 1
src/Services/Gateway/PaymentWall.php

@@ -13,7 +13,7 @@ use Paymentwall_Config;
 use Paymentwall_Pingback;
 use Paymentwall_Widget;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class PaymentWall extends AbstractPayment

+ 1 - 1
src/Services/Gateway/StripeCard.php

@@ -9,7 +9,7 @@ use App\Models\Setting;
 use App\Services\Auth;
 use App\Services\View;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class StripeCard extends AbstractPayment

+ 1 - 1
src/Services/Gateway/THeadPay.php

@@ -10,7 +10,7 @@ use App\Services\Auth;
 use App\Services\View;
 use Exception;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class THeadPay extends AbstractPayment

+ 1 - 1
src/Services/Gateway/Vmqpay.php

@@ -8,7 +8,7 @@ use App\Models\Paylist;
 use App\Models\Setting;
 use App\Services\Auth;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Request;
+use Slim\Http\ServerRequest;
 use Slim\Http\Response;
 
 final class Vmqpay extends AbstractPayment