浏览代码

Merge pull request #2333 from SSPanel-UIM/dev

Dev 20240108
M1Screw 1 年之前
父节点
当前提交
3dbeacc99d

+ 24 - 5
app/routes.php

@@ -142,7 +142,14 @@ return static function (Slim\App $app): void {
         $group->get('/node/create', App\Controllers\Admin\NodeController::class . ':create');
         $group->post('/node', App\Controllers\Admin\NodeController::class . ':add');
         $group->get('/node/{id:[0-9]+}/edit', App\Controllers\Admin\NodeController::class . ':edit');
-        $group->post('/node/{id:[0-9]+}/reset', App\Controllers\Admin\NodeController::class . ':reset');
+        $group->post(
+            '/node/{id:[0-9]+}/reset_password',
+            App\Controllers\Admin\NodeController::class . ':resetPassword'
+        );
+        $group->post(
+            '/node/{id:[0-9]+}/reset_bandwidth',
+            App\Controllers\Admin\NodeController::class . ':resetBandwidth'
+        );
         $group->post('/node/{id:[0-9]+}/copy', App\Controllers\Admin\NodeController::class . ':copy');
         $group->put('/node/{id:[0-9]+}', App\Controllers\Admin\NodeController::class . ':update');
         $group->delete('/node/{id:[0-9]+}', App\Controllers\Admin\NodeController::class . ':delete');
@@ -246,10 +253,22 @@ return static function (Slim\App $app): void {
         $group->get('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':index');
         $group->post('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':save');
         // 设置测试
-        $group->post('/setting/test/email', App\Controllers\Admin\Setting\EmailController::class . ':testEmail');
-        $group->post('/setting/test/telegram', App\Controllers\Admin\Setting\ImController::class . ':testTelegram');
-        $group->post('/setting/test/discord', App\Controllers\Admin\Setting\ImController::class . ':testDiscord');
-        $group->post('/setting/test/slack', App\Controllers\Admin\Setting\ImController::class . ':testSlack');
+        $group->post(
+            '/setting/test/email',
+            App\Controllers\Admin\Setting\EmailController::class . ':testEmail'
+        );
+        $group->post(
+            '/setting/test/telegram',
+            App\Controllers\Admin\Setting\ImController::class . ':testTelegram'
+        );
+        $group->post(
+            '/setting/test/discord',
+            App\Controllers\Admin\Setting\ImController::class . ':testDiscord'
+        );
+        $group->post(
+            '/setting/test/slack',
+            App\Controllers\Admin\Setting\ImController::class . ':testSlack'
+        );
         // 礼品卡
         $group->get('/giftcard', App\Controllers\Admin\GiftCardController::class . ':index');
         $group->post('/giftcard', App\Controllers\Admin\GiftCardController::class . ':add');

+ 9 - 9
composer.json

@@ -15,7 +15,7 @@
         "ext-yaml": "*",
         "ext-zip": "*",
         "anankke/omnipay-alipay": "^3.1.3",
-        "aws/aws-sdk-php": "^3.293.2",
+        "aws/aws-sdk-php": "^3",
         "geoip2/geoip2": "^3",
         "guzzlehttp/guzzle": "^7.8.1",
         "guzzlehttp/psr7": "^2.6.2",
@@ -24,26 +24,26 @@
         "irazasyed/telegram-bot-sdk": "^3.13",
         "lcobucci/jwt": "^5.2",
         "league/omnipay": "^3.2.1",
-        "mailgun/mailgun-php": "^3.6.3",
+        "mailgun/mailgun-php": "^4",
         "nikolaposa/rate-limit": "^3.0",
         "openai-php/client": "^0",
         "ozdemir/datatables": "^2.3.7",
         "phpmailer/phpmailer": "^6.9.1",
         "postal/postal": "^2",
         "ramsey/uuid": "^4.7.5",
-        "sendgrid/sendgrid": "^8.1.0",
+        "sendgrid/sendgrid": "^8",
         "sentry/sdk": "^4",
         "slim/http": "^1.3",
         "slim/slim": "^4.12",
         "smarty/smarty": "^4.3.4",
-        "srmklive/paypal": "^3.0.27",
+        "srmklive/paypal": "^3",
         "stripe/stripe-php": "^13",
-        "symfony/http-client": "^7.0",
-        "symfony/translation": "^6.4",
+        "symfony/http-client": "^7",
+        "symfony/translation": "^6",
         "tronovav/geoip2-update": "^2.3.1",
-        "twig/twig": "^3.8",
-        "vectorface/googleauthenticator": "^3.0",
-        "voku/anti-xss": "^4.1.42"
+        "twig/twig": "^3",
+        "vectorface/googleauthenticator": "^3",
+        "voku/anti-xss": "^4"
     },
     "autoload": {
         "psr-4": {

文件差异内容过多而无法显示
+ 175 - 171
composer.lock


+ 8 - 6
config/.config.example.php

@@ -32,12 +32,14 @@ $_ENV['db_collation'] = 'utf8mb4_unicode_ci';
 $_ENV['db_prefix']    = '';
 
 //Redis设置-------------------------------------------------------------------------------------------
-$_ENV['redis_host']     = '127.0.0.1';        //Redis地址
-$_ENV['redis_port']     = 6379;               //Redis端口
-$_ENV['redis_timeout']  = 2;                  //Redis连接超时时间,单位秒
-$_ENV['redis_username'] = '';                 //Redis用户名,留空则不使用用户名连接
-$_ENV['redis_password'] = '';                 //Redis密码,留空则无密码
-$_ENV['redis_ssl']      = false;              //是否使用SSL连接Redis,如果使用了SSL,那么Redis端口应为Redis实例的TLS端口
+$_ENV['redis_host']            = '127.0.0.1';    //Redis地址,使用unix domain socket时填写文件路径
+$_ENV['redis_port']            = 6379;           //Redis端口,使用unix domain socket时填写-1
+$_ENV['redis_connect_timeout'] = 2.0;            //Redis连接超时时间,单位秒
+$_ENV['redis_read_timeout']    = 8.0;            //Redis读取超时时间,单位秒
+$_ENV['redis_username']        = '';             //Redis用户名,留空则不使用用户名连接
+$_ENV['redis_password']        = '';             //Redis密码,留空则无密码
+$_ENV['redis_ssl']             = false;          //是否使用SSL连接Redis,如果使用了SSL,那么Redis端口应为Redis实例的TLS端口
+$_ENV['redis_ssl_context']     = [];             //使用SSL时的上下文选项,参考 https://www.php.net/manual/zh/context.ssl.php
 
 //Rate Limit设置--------------------------------------------------------------------------------------------
 $_ENV['enable_rate_limit']    = true;            //是否开启请求限制

+ 35 - 69
config/appprofile.example.php

@@ -53,44 +53,14 @@ $_ENV['SingBox_Config'] = [
                 'tag' => 'local',
                 'address' => 'local',
             ],
-            [
-                'tag' => 'cloudflare',
-                'address' => 'https://1.1.1.1/dns-query',
-                'address_resolver' => 'local',
-            ],
-            [
-                'tag' => 'dnspod',
-                'address' => 'https://1.12.12.12/dns-query',
-                'detour' => 'direct',
-            ],
         ],
         'rules' => [
             [
                 'outbound' => 'any',
-                'server' => 'dnspod',
-            ],
-            [
-                'clash_mode' => 'Direct',
-                'server' => 'dnspod',
-            ],
-            [
-                'clash_mode' => 'Global',
-                'server' => 'cloudflare',
-            ],
-            [
-                'type' => 'logical',
-                'mode' => 'and',
-                'rules' => [
-                    [
-                        'geosite' => [
-                            'cn',
-                        ],
-                    ],
-                ],
-                'server' => 'dnspod',
+                'server' => 'local',
             ],
         ],
-        'final' => 'cloudflare',
+        'final' => 'local',
         'strategy' => 'prefer_ipv6',
     ],
     'inbounds' => [
@@ -132,34 +102,17 @@ $_ENV['SingBox_Config'] = [
             'type' => 'block',
             'tag' => 'block',
         ],
-        [
-            'type' => 'dns',
-            'tag' => 'dns',
-        ],
     ],
     'route' => [
-        'geoip' => [
-            'download_url' => 'https://' . $_ENV['jsdelivr_url'] . '/gh/MetaCubeX/meta-rules-dat@release/geoip-lite.db',
-            'download_detour' => 'direct',
-        ],
-        'geosite' => [
-            'download_url' => 'https://' . $_ENV['jsdelivr_url'] . '/gh/MetaCubeX/meta-rules-dat@release/geosite-lite.db',
-            'download_detour' => 'direct',
-        ],
         'rules' => [
-            [
-                'protocol' => 'dns',
-                'outbound' => 'dns',
-            ],
-            [
-                'network' => 'udp',
-                'port' => 53,
-                'outbound' => 'dns',
-            ],
             [
                 'clash_mode' => 'Direct',
                 'outbound' => 'direct',
             ],
+            [
+                'clash_mode' => 'Rule',
+                'outbound' => 'default',
+            ],
             [
                 'clash_mode' => 'Global',
                 'outbound' => 'default',
@@ -169,30 +122,43 @@ $_ENV['SingBox_Config'] = [
                 'outbound' => 'block',
             ],
             [
-                'type' => 'logical',
-                'mode' => 'and',
-                'rules' => [
-                    [
-                        'geosite' => [
-                            'cn',
-                        ],
-                        'geoip' => [
-                            'cn',
-                            'private',
-                        ],
-                    ],
-                ],
+                'ip_is_private' => true,
+                'outbound' => 'direct',
+            ],
+            [
+                'rule_set' => 'geoip-cn',
+                'outbound' => 'direct',
+            ],
+            [
+                'rule_set' => 'geosite-cn',
                 'outbound' => 'direct',
             ],
         ],
+        'rule_set' => [
+            [
+                'tag' => 'geoip-cn',
+                'type' => 'remote',
+                'format' => 'binary',
+                'url' => 'https://' . $_ENV['jsdelivr_url'] . '/gh/SagerNet/sing-geoip@rule-set/geoip-cn.srs',
+                'download_detour' => 'direct',
+            ],
+            [
+                'tag' => 'geosite-cn',
+                'type' => 'remote',
+                'format' => 'binary',
+                'url' => 'https://' . $_ENV['jsdelivr_url'] . '/gh/SagerNet/sing-geosite@rule-set/geosite-cn.srs',
+                'download_detour' => 'direct',
+            ],
+        ],
         'auto_detect_interface' => true,
     ],
     'experimental' => [
+        'cache_file' => [
+            'enabled' => true,
+            'cache_id' => '',
+        ],
         'clash_api' => [
             'external_controller' => '127.0.0.1:9090',
-            'store_mode' => true,
-            'store_selected' => true,
-            'cache_id' => '',
         ],
     ],
 ];

+ 24 - 4
resources/views/tabler/admin/node/edit.tpl

@@ -163,11 +163,14 @@
                                 <span>流量设置</span>
                             </div>
                             <div class="form-group mb-3 row">
-                                <label class="form-label col-3 col-form-label">已用流量 (GB)</label>
+                                <label class="form-label col-3 col-form-label">已用流量</label>
                                 <div class="col">
                                     <input id="node_bandwidth" type="text" class="form-control"
                                            value="{$node->node_bandwidth}" disabled="">
                                 </div>
+                                <div class="col-auto">
+                                    <button id="reset-bandwidth" class="btn btn-red">重置</button>
+                                </div>
                             </div>
                             <div class="form-group mb-3 row">
                                 <label class="form-label col-3 col-form-label">可用流量 (GB)</label>
@@ -199,7 +202,7 @@
                                        disabled="">
                                 <div class="row my-3">
                                     <div class="col">
-                                        <button id="reset-node-password" class="btn btn-red">重置</button>
+                                        <button id="reset-password" class="btn btn-red">重置</button>
                                         <button id="copy-password" class="copy btn btn-primary"
                                                 data-clipboard-text="{$node->password}">
                                             复制
@@ -232,9 +235,26 @@
     const editor = new JSONEditor(container, options);
     editor.set({$node->custom_config})
 
-    $("#reset-node-password").click(function () {
+    $("#reset-bandwidth").click(function () {
+        $.ajax({
+            url: '/admin/node/{$node->id}/reset_bandwidth',
+            type: 'POST',
+            dataType: "json",
+            success: function (data) {
+                if (data.ret === 1) {
+                    $('#success-message').text(data.msg);
+                    $('#success-dialog').modal('show');
+                } else {
+                    $('#fail-message').text(data.msg);
+                    $('#fail-dialog').modal('show');
+                }
+            }
+        })
+    });
+
+    $("#reset-password").click(function () {
         $.ajax({
-            url: '/admin/node/{$node->id}/reset',
+            url: '/admin/node/{$node->id}/reset_password',
             type: 'POST',
             dataType: "json",
             success: function (data) {

+ 72 - 57
src/Command/Tool.php

@@ -31,25 +31,27 @@ use const JSON_PRETTY_PRINT;
 use const JSON_UNESCAPED_UNICODE;
 use const PHP_EOL;
 use const STDIN;
+use const STDOUT;
 
 final class Tool extends Command
 {
     public string $description = <<<EOL
 ├─=: php xcat Tool [选项]
 │ ├─ setTelegram             - 设置 Telegram 机器人
-│ ├─ resetAllSettings        - 使用默认值覆盖设置中心设
-│ ├─ exportAllSettings       - 导出所有设
-│ ├─ importAllSettings       - 导入所有设
+│ ├─ resetSetting            - 使用默认值覆盖数据库配
+│ ├─ exportSetting           - 导出数据库配
+│ ├─ importSetting           - 导入数据库配
 │ ├─ resetNodePassword       - 重置所有节点通讯密钥
-│ ├─ resetPort               - 重置单个用户端口
-│ ├─ createAdmin             - 创建管理员帐号
-│ ├─ resetAllPort            - 重置所有用户端口
-│ ├─ resetTraffic            - 重置所有用户流量
+│ ├─ resetNodeBandwidth      - 重置所有节点流量
+│ ├─ resetPort               - 重置所有用户端口
+│ ├─ resetBandwidth          - 重置所有用户流量
+│ ├─ resetPassword           - 重置所有用户密码
 │ ├─ clearSubToken           - 清除用户 Sub Token
 │ ├─ generateUUID            - 为所有用户生成新的 UUID
 │ ├─ generateGa              - 为所有用户生成新的 Ga Secret
 │ ├─ generateApiToken        - 为所有用户生成新的 API Token
 │ ├─ setTheme                - 为所有用户设置新的主题
+│ ├─ createAdmin             - 创建管理员帐号
 
 EOL;
 
@@ -83,7 +85,7 @@ EOL;
         }
     }
 
-    public function resetAllSettings(): void
+    public function resetSetting(): void
     {
         $settings = Config::all();
 
@@ -95,7 +97,7 @@ EOL;
         echo '已使用默认值覆盖所有数据库设置' . PHP_EOL;
     }
 
-    public function exportAllSettings(): void
+    public function exportSetting(): void
     {
         $settings = Config::all();
 
@@ -113,7 +115,7 @@ EOL;
         echo '已导出所有数据库设置' . PHP_EOL;
     }
 
-    public function importAllSettings(): void
+    public function importSetting(): void
     {
         $json_settings = file_get_contents('./config/settings.json');
         $settings = json_decode($json_settings, true);
@@ -187,58 +189,69 @@ EOL;
         echo '已重置所有节点密码' . PHP_EOL;
     }
 
-    /**
-     * 重置用户端口
-     */
-    public function resetPort(): void
+    public function resetNodeBandwidth(): void
     {
-        fwrite(STDOUT, '请输入用户id: ');
-        $user = (new ModelsUser())->find(trim(fgets(STDIN)));
+        $nodes = Node::all();
 
-        if ($user !== null) {
-            $user->port = Tools::getSsPort();
-            if ($user->save()) {
-                echo '重置成功!';
-            }
-        } else {
-            echo '用户不存在';
+        foreach ($nodes as $node) {
+            $node->node_bandwidth = 0;
+            $node->save();
         }
+
+        echo '已重置所有节点流量' . PHP_EOL;
     }
 
     /**
      * 重置所有用户端口
      */
-    public function resetAllPort(): void
+    public function resetPort(): void
     {
         $users = ModelsUser::all();
 
+        if (count($users) === 0 || count($users) >= 65535) {
+            echo '无效的用户数量' . PHP_EOL;
+            return;
+        }
+
+        (new ModelsUser())->update([
+            'port' => 0,
+        ]);
+
         foreach ($users as $user) {
-            $origin_port = $user->port;
             $user->port = Tools::getSsPort();
-            echo '$origin_port=' . $origin_port . '&$user->port=' . $user->port . PHP_EOL;
             $user->save();
         }
 
-        echo 'reset all ports successful';
+        echo '已重置所有用户端口' . PHP_EOL;
     }
 
     /**
      * 重置所有用户流量
      */
-    public function resetTraffic(): void
+    public function resetBandwidth(): void
     {
-        try {
-            (new ModelsUser())->where('is_banned', 0)->update([
-                'd' => 0,
-                'u' => 0,
-                'transfer_today' => 0,
-            ]);
-        } catch (Exception $e) {
-            echo $e->getMessage();
-            return;
+        (new ModelsUser())->where('is_banned', 0)->update([
+            'd' => 0,
+            'u' => 0,
+            'transfer_today' => 0,
+        ]);
+
+        echo '已重置所有用户流量' . PHP_EOL;
+    }
+
+    /**
+     * 重置所有用户密码
+     */
+    public function resetPassword(): void
+    {
+        $users = ModelsUser::all();
+
+        foreach ($users as $user) {
+            $user->pass = Hash::passwordHash(Tools::genRandomChar(32));
+            $user->save();
         }
 
-        echo 'reset traffic successful';
+        echo '已重置所有用户密码' . PHP_EOL;
     }
 
     /**
@@ -248,7 +261,7 @@ EOL;
     {
         Link::query()->truncate();
 
-        echo 'clear Sub Token successful';
+        echo '已清除所有用户 Sub Token' . PHP_EOL;
     }
 
     /**
@@ -263,7 +276,7 @@ EOL;
             $user->save();
         }
 
-        echo 'generate UUID successful';
+        echo '已为所有用户生成新的 UUID' . PHP_EOL;
     }
 
     /**
@@ -282,7 +295,7 @@ EOL;
             }
         }
 
-        echo 'generate Ga Secret successful';
+        echo '已为所有用户生成新的 Ga Secret' . PHP_EOL;
     }
 
     /**
@@ -296,7 +309,24 @@ EOL;
             $user->generateApiToken();
         }
 
-        echo 'generate Api Token successful';
+        echo '已为所有用户生成新的 Api Token' . PHP_EOL;
+    }
+
+    /**
+     * 为所有用户设置新的主题
+     */
+    public function setTheme(): void
+    {
+        fwrite(STDOUT, '请输入要设置的主题名称: ');
+        $theme = trim(fgets(STDIN));
+        $users = ModelsUser::all();
+
+        foreach ($users as $user) {
+            $user->theme = $theme;
+            $user->save();
+        }
+
+        echo '已为所有用户设置新的主题: ' . $theme . PHP_EOL;
     }
 
     /**
@@ -366,19 +396,4 @@ EOL;
             echo '已取消创建' . PHP_EOL;
         }
     }
-
-    /**
-     * 为所有用户设置新的主题
-     */
-    public function setTheme(): void
-    {
-        fwrite(STDOUT, '请输入要设置的主题名称: ');
-        $theme = trim(fgets(STDIN));
-        $users = ModelsUser::all();
-
-        foreach ($users as $user) {
-            $user->theme = $theme;
-            $user->save();
-        }
-    }
 }

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

@@ -102,9 +102,9 @@ final class NodeController extends BaseController
         $node->dynamic_rate_type = $request->getParam('dynamic_rate_type') ?? 0;
         $node->dynamic_rate_config = json_encode([
             'max_rate' => $request->getParam('max_rate') ?? 1,
-            'max_rate_time' => $request->getParam('max_rate_time') ?? 3,
+            'max_rate_time' => $request->getParam('max_rate_time') ?? 22,
             'min_rate' => $request->getParam('min_rate') ?? 1,
-            'min_rate_time' => $request->getParam('min_rate_time') ?? 22,
+            'min_rate_time' => $request->getParam('min_rate_time') ?? 3,
         ]);
 
         $custom_config = $request->getParam('custom_config') ?? '{}';
@@ -167,11 +167,11 @@ final class NodeController extends BaseController
 
         $dynamic_rate_config = json_decode($node->dynamic_rate_config);
         $node->max_rate = $dynamic_rate_config?->max_rate ?? 1;
-        $node->max_rate_time = $dynamic_rate_config?->max_rate_time ?? 3;
+        $node->max_rate_time = $dynamic_rate_config?->max_rate_time ?? 22;
         $node->min_rate = $dynamic_rate_config?->min_rate ?? 1;
-        $node->min_rate_time = $dynamic_rate_config?->min_rate_time ?? 22;
+        $node->min_rate_time = $dynamic_rate_config?->min_rate_time ?? 3;
 
-        $node->node_bandwidth = Tools::flowToGB($node->node_bandwidth);
+        $node->node_bandwidth = Tools::autoBytes($node->node_bandwidth);
         $node->node_bandwidth_limit = Tools::flowToGB($node->node_bandwidth_limit);
 
         return $response->write(
@@ -248,7 +248,7 @@ final class NodeController extends BaseController
         ]);
     }
 
-    public function reset(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function resetPassword(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $node = (new Node())->find($args['id']);
         $node->password = Tools::genRandomChar(32);
@@ -260,6 +260,18 @@ final class NodeController extends BaseController
         ]);
     }
 
+    public function resetBandwidth(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $node = (new Node())->find($args['id']);
+        $node->node_bandwidth = 0;
+        $node->save();
+
+        return $response->withJson([
+            'ret' => 1,
+            'msg' => '重置节点流量成功',
+        ]);
+    }
+
     /**
      * 后台删除指定节点
      */

+ 5 - 1
src/Controllers/SubController.php

@@ -75,7 +75,11 @@ final class SubController extends BaseController
         . '; expire=' . strtotime($user->class_expire);
 
         if (Config::obtain('subscribe_log')) {
-            (new SubscribeLog())->add($user, $subtype, $this->antiXss->xss_clean($request->getHeaderLine('User-Agent')));
+            (new SubscribeLog())->add(
+                $user,
+                $subtype,
+                $this->antiXss->xss_clean($request->getHeaderLine('User-Agent'))
+            );
         }
 
         return $response->withHeader('Subscription-Userinfo', $sub_details)

+ 18 - 16
src/Services/Cache.php

@@ -5,33 +5,35 @@ declare(strict_types=1);
 namespace App\Services;
 
 use Redis;
-use RedisException;
 
 final class Cache
 {
-    /**
-     * @throws RedisException
-     */
     public function initRedis(): Redis
     {
-        $redis = new Redis();
-        $redis->connect($_ENV['redis_host'], $_ENV['redis_port']);
-
-        if ($_ENV['redis_password'] !== '') {
-            $redis->auth($_ENV['redis_password']);
-        }
-
-        return $redis;
+        return new Redis(self::getRedisConfig());
     }
 
     public static function getRedisConfig(): array
     {
-        return [
+        $config = [
             'host' => $_ENV['redis_host'],
             'port' => $_ENV['redis_port'],
-            'connectTimeout' => $_ENV['redis_timeout'],
-            'auth' => [$_ENV['redis_username'], $_ENV['redis_password']],
-            'ssl' => ['verify_peer' => $_ENV['redis_ssl']],
+            'connectTimeout' => $_ENV['redis_connect_timeout'],
+            'readTimeout' => $_ENV['redis_read_timeout'],
         ];
+
+        if ($_ENV['redis_username'] !== '') {
+            $config['auth']['user'] = $_ENV['redis_username'];
+        }
+
+        if ($_ENV['redis_password'] !== '') {
+            $config['auth']['pass'] = $_ENV['redis_password'];
+        }
+
+        if ($_ENV['redis_ssl']) {
+            $config['ssl'] = $_ENV['redis_ssl_context'];
+        }
+
+        return $config;
     }
 }

+ 9 - 5
src/Services/Subscribe/SingBox.php

@@ -34,7 +34,8 @@ final class SingBox extends Base
 
                     break;
                 case 1:
-                    $ss_2022_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
+                    $ss_2022_port = $node_custom_config['offset_port_user'] ??
+                        ($node_custom_config['offset_port_node'] ?? 443);
                     $method = $node_custom_config['method'] ?? '2022-blake3-aes-128-gcm';
 
                     $pk_len = match ($method) {
@@ -56,7 +57,8 @@ final class SingBox extends Base
 
                     break;
                 case 2:
-                    $tuic_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
+                    $tuic_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'] ?? false;
                     $congestion_control = $node_custom_config['congestion_control'] ?? 'bbr';
@@ -81,7 +83,8 @@ final class SingBox extends Base
 
                     break;
                 case 11:
-                    $v2_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
+                    $v2_port = $node_custom_config['offset_port_user'] ??
+                        ($node_custom_config['offset_port_node'] ?? 443);
                     $transport = ($node_custom_config['network'] ?? '') === 'tcp' ? '' : $node_custom_config['network'];
                     $host = $node_custom_config['header']['request']['headers']['Host'][0] ??
                         $node_custom_config['host'] ?? '';
@@ -113,7 +116,8 @@ final class SingBox extends Base
 
                     break;
                 case 14:
-                    $trojan_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
+                    $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';
                     $transport = $node_custom_config['network'] ?? '';
@@ -158,7 +162,7 @@ final class SingBox extends Base
         }
 
         $singbox_config['outbounds'] = array_merge($singbox_config['outbounds'], $nodes);
-        $singbox_config['experimental']['clash_api']['cache_id'] = $_ENV['appName'];
+        $singbox_config['experimental']['cache_file']['cache_id'] = $_ENV['appName'];
 
         return json_encode($singbox_config);
     }

+ 28 - 21
src/Utils/Tools.php

@@ -15,6 +15,7 @@ use function array_flip;
 use function base64_encode;
 use function bin2hex;
 use function closedir;
+use function count;
 use function date;
 use function explode;
 use function filter_var;
@@ -49,42 +50,42 @@ final class Tools
      * @param string $ip
      *
      * @return string
-     *
-     * @throws InvalidDatabaseException
      */
     public static function getIpLocation(string $ip): string
     {
-        $err_msg = '';
+        $data = 'GeoIP2 服务未配置';
         $city = null;
         $country = null;
 
-        if ($_ENV['maxmind_license_key'] === '') {
-            $err_msg = 'GeoIP2 服务未配置';
-        } else {
-            $geoip = new GeoIP2();
+        if ($_ENV['maxmind_license_key'] !== '') {
+            try {
+                $geoip = new GeoIP2();
+            } catch (InvalidDatabaseException $e) {
+                return $data;
+            }
 
             try {
                 $city = $geoip->getCity($ip);
-            } catch (AddressNotFoundException $e) {
+            } catch (AddressNotFoundException|InvalidDatabaseException $e) {
                 $city = '未知城市';
             }
 
             try {
                 $country = $geoip->getCountry($ip);
-            } catch (AddressNotFoundException $e) {
+            } catch (AddressNotFoundException|InvalidDatabaseException $e) {
                 $country = '未知国家';
             }
         }
 
         if ($city !== null) {
-            return $city . ', ' . $country;
+            $data = $city . ', ' . $country;
         }
 
         if ($country !== null) {
-            return $country;
+            $data = $country;
         }
 
-        return $err_msg;
+        return $data;
     }
 
     /**
@@ -159,9 +160,9 @@ final class Tools
         return round(pow(1000, $base - floor($base)), $precision) . $units[floor($base)];
     }
 
-    //虽然名字是toMB,但是实际上功能是from MB to B
-
     /**
+     * 虽然名字是toMB,但是实际上功能是from MB to B
+     *
      * @param $traffic
      *
      * @return int
@@ -171,9 +172,9 @@ final class Tools
         return (int) $traffic * 1048576;
     }
 
-    //虽然名字是toGB,但是实际上功能是from GB to B
-
     /**
+     * 虽然名字是toGB,但是实际上功能是from GB to B
+     *
      * @param $traffic
      *
      * @return int
@@ -244,16 +245,21 @@ final class Tools
 
     public static function getSsPort(): int
     {
-        if (Config::obtain('min_port') > 65535
-            || Config::obtain('min_port') <= 0
-            || Config::obtain('max_port') > 65535
-            || Config::obtain('max_port') <= 0
+        $max_port = Config::obtain('max_port');
+        $min_port = Config::obtain('min_port');
+
+        if ($min_port >= 65535
+            || $min_port <= 0
+            || $max_port > 65535
+            || $max_port <= 0
+            || $min_port > $max_port
+            || count(User::all()) >= $max_port - $min_port + 1
         ) {
             return 0;
         }
 
         $det = (new User())->pluck('port')->toArray();
-        $port = array_diff(range(Config::obtain('min_port'), Config::obtain('max_port')), $det);
+        $port = array_diff(range($min_port, $max_port), $det);
         shuffle($port);
 
         return $port[0];
@@ -422,6 +428,7 @@ final class Tools
 
     /**
      * 判断是否 JSON
+     * TODO: Remove this function when PHP 8.3 is minimum requirement and replace it with native function
      *
      * @param string $string
      *

+ 4 - 4
update.sh

@@ -4,7 +4,7 @@ cat << "EOF"
 SSPanel-UIM update script
 Author: M1Screw
 Github: https://github.com/sspanel-uim/SSPanel-Uim-Dev
-Usage: 
+Usage:
 ./update.sh dev --> Upgrade to the latest development version
 ./update.sh release $release_version $db_version --> Upgrade to the release version with the specified database version
 ./update.sh release-nogit --> Upgrade to the current release version without git(You will need to manually download the latest release version)
@@ -18,7 +18,7 @@ do_update_sspanel_dev(){
     php composer.phar install --no-dev
     php composer.phar selfupdate
     php xcat Update
-    php xcat Tool importAllSettings
+    php xcat Tool importSetting
     php xcat Migration latest
 }
 
@@ -31,7 +31,7 @@ do_update_sspanel_release(){
     php composer.phar install --no-dev
     php composer.phar selfupdate
     php xcat Update
-    php xcat Tool importAllSettings
+    php xcat Tool importSetting
     php xcat Migration $db_version
 }
 
@@ -40,7 +40,7 @@ do_update_sspanel_release_nogit(){
     php composer.phar install --no-dev
     php composer.phar selfupdate
     php xcat Update
-    php xcat Tool importAllSettings
+    php xcat Tool importSetting
     php xcat Migration latest
 }
 

部分文件因为文件数量过多而无法显示