Browse Source

Merge pull request #2365 from SSPanel-UIM/dev

Dev 20240219
M1Screw 1 year ago
parent
commit
94ae8aa4f1

+ 15 - 8
README.md

@@ -24,27 +24,34 @@
 
 ## 简介 / TL;DR
 
-SSPanel UIM 是一款专为 Shadowsocks / V2Ray / Trojan / TUIC 协议设计的多用途代理服务销售管理系统。  
+SSPanel UIM 是一款专为 Shadowsocks(包括 2022 Edition) / V2Ray / Trojan / TUIC 协议设计的多用途代理服务销售管理系统。  
 SSPanel UIM is a multi-purpose proxy service sales management system designed for Shadowsocks / V2Ray / Trojan / TUIC protocol.
 
 ## 特性 / Features
 
 - 集成 支付宝当面付,PayPal,Stripe 等多种支付系统
-- Integrate multiple payment systems such as Alipay, PayPal, Stripe, etc.
 - 支持多种邮件服务,内置邮件队列功能,无需第三方组件即可使用
-- Support multiple mail services, built-in mail queue function, no third-party components are required to use
 - 内置基于 Bootstrap 5 的 tabler 主题,模板引擎支持
-- Built-in tabler theme based on Bootstrap 5, template engine support
 - 支持 Shadowsocks 2022,TUIC 等最新代理协议
+- 通用订阅接口,一键 json/clash/sip008/sing-box/v2ray-json 格式订阅下发
+- 自定义节点配置,模块化订阅系统,支持多种客户端专用订阅格式
+- 重构的商店系统,支持包括但不限于包年包月,按量计费,接入类型计费等计费模式
+- 重构的定时任务系统,一个命令即可自动完成所有定时任务
+- 深度集成大型语言模型(Large Language Model),支持工单智能回复,文档生成等功能
+- 一键对接 OpenAI,Gemini Pro,Hugging Face Hosted API 和 Cloudflare Workers AI 等人工智能服务
+
+
+
+- Integrate multiple payment systems such as Alipay F2F, PayPal, Stripe, etc.
+- Support multiple mail services, built-in mail queue function, no third-party components are required to use
+- Built-in tabler theme based on Bootstrap 5, template engine support
 - Support Shadowsocks 2022, TUIC and other latest proxy protocols
-- 通用订阅接口,一键 json/clash/sip008/sing-box 格式订阅下发
 - Universal subscription interface, one-click json/clash/sip008/sing-box format subscription distribution
-- 自定义节点配置,模块化订阅系统,支持多种客户端专用订阅格式
 - Custom node configuration, modular subscription system, support multiple client-specific subscription formats
-- 重构的商店系统,支持包括但不限于包年包月,按量计费,接入类型计费等计费模式
 - Refactored store system, support billing modes including but not limited to annual/monthly, pay-as-you-go, access type billing, etc.
-- 重构的定时任务系统,一个命令即可自动完成所有定时任务
 - Refactored scheduled task system, one command can automatically complete all scheduled tasks
+- Deep integration of large language models, support intelligent reply to ticket, document generation and other functions
+- One-click access to OpenAI, Gemini Pro, Hugging Face Hosted API, Cloudflare Workers AI and other artificial intelligence services
 
 ## 安装 / Installation
 

+ 3 - 4
composer.json

@@ -14,16 +14,15 @@
         "ext-xml": "*",
         "ext-yaml": "*",
         "ext-zip": "*",
-        "anankke/omnipay-alipay": "^3",
+        "alipaysdk/openapi": "*@dev",
         "aws/aws-sdk-php": "^3",
         "geoip2/geoip2": "^3",
         "guzzlehttp/guzzle": "^7",
         "guzzlehttp/psr7": "^2",
-        "illuminate/database": "^10",
-        "illuminate/pagination": "^10",
+        "illuminate/database": "^10.44.0",
+        "illuminate/pagination": "^10.44.0",
         "irazasyed/telegram-bot-sdk": "^3",
         "lcobucci/jwt": "^5",
-        "league/omnipay": "^3",
         "mailgun/mailgun-php": "^4",
         "nikolaposa/rate-limit": "^3",
         "openai-php/client": "^0",

+ 83 - 595
composer.lock

@@ -4,68 +4,69 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "cb81eb357e69b4ed5d997458ce65a411",
+    "content-hash": "29d028fe09575d21b97024d48e6f4ebf",
     "packages": [
         {
-            "name": "anankke/omnipay-alipay",
-            "version": "v3.1.3",
+            "name": "alipaysdk/openapi",
+            "version": "dev-master",
             "source": {
                 "type": "git",
-                "url": "https://github.com/Anankke/omnipay-alipay.git",
-                "reference": "66b20f5e66b88be1214b9b859de5d5318b49fe90"
+                "url": "https://github.com/alipay/alipay-sdk-php-all.git",
+                "reference": "f570f7f978c18677da934913d191eb9da89ecfc6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Anankke/omnipay-alipay/zipball/66b20f5e66b88be1214b9b859de5d5318b49fe90",
-                "reference": "66b20f5e66b88be1214b9b859de5d5318b49fe90",
+                "url": "https://api.github.com/repos/alipay/alipay-sdk-php-all/zipball/f570f7f978c18677da934913d191eb9da89ecfc6",
+                "reference": "f570f7f978c18677da934913d191eb9da89ecfc6",
                 "shasum": ""
             },
             "require": {
                 "ext-bcmath": "*",
+                "ext-curl": "*",
+                "ext-dom": "*",
                 "ext-json": "*",
+                "ext-mbstring": "*",
                 "ext-openssl": "*",
-                "omnipay/common": "^3.0",
-                "php-http/guzzle7-adapter": "^1"
+                "guzzlehttp/guzzle": "^7.3",
+                "guzzlehttp/psr7": "^1.7 || ^2.0",
+                "php": "^7.4 || ^8.0"
             },
             "require-dev": {
-                "omnipay/tests": "^3.0",
-                "squizlabs/php_codesniffer": "^3.4"
+                "friendsofphp/php-cs-fixer": "^3.5",
+                "phpunit/phpunit": "^8.0 || ^9.0"
             },
+            "default-branch": true,
             "type": "library",
             "autoload": {
-                "files": [
-                    "src/Common/helpers.php"
-                ],
                 "psr-4": {
-                    "Omnipay\\Alipay\\": "src/",
-                    "Omnipay\\Alipay\\Tests\\": "tests/"
+                    "Alipay\\OpenAPISDK\\": "v3/src/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "MIT"
+                "unlicense"
             ],
             "authors": [
                 {
-                    "name": "Loki Else",
-                    "email": "[email protected]"
+                    "name": "OpenAPI-Generator contributors",
+                    "homepage": "https://openapi-generator.tech"
                 }
             ],
-            "description": "Alipay gateway for Omnipay payment processing library",
-            "homepage": "https://github.com/lokielse/omnipay-alipay",
+            "description": "支付宝开放平台v3协议文档",
+            "homepage": "https://openapi-generator.tech",
             "keywords": [
-                "alipay",
-                "gateway",
-                "merchant",
-                "omnipay",
-                "pay",
-                "payment",
-                "purchase"
+                "api",
+                "openapi",
+                "openapi-generator",
+                "openapitools",
+                "php",
+                "rest",
+                "sdk"
             ],
             "support": {
-                "source": "https://github.com/Anankke/omnipay-alipay/tree/v3.1.3"
+                "source": "https://github.com/alipay/alipay-sdk-php-all/tree/master"
             },
-            "time": "2022-04-23T09:09:28+00:00"
+            "time": "2024-01-25T09:33:38+00:00"
         },
         {
             "name": "aws/aws-crt-php",
@@ -123,16 +124,16 @@
         },
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.298.7",
+            "version": "3.299.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "b4d98bfc70df146774bf9b04f5ac5b39955fbad2"
+                "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b4d98bfc70df146774bf9b04f5ac5b39955fbad2",
-                "reference": "b4d98bfc70df146774bf9b04f5ac5b39955fbad2",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a0f87b8e8bfb9afd0ffd702fcda556b465eee457",
+                "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457",
                 "shasum": ""
             },
             "require": {
@@ -212,9 +213,9 @@
             "support": {
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.298.7"
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.299.1"
             },
-            "time": "2024-02-09T19:07:04+00:00"
+            "time": "2024-02-16T19:08:34+00:00"
         },
         {
             "name": "bacon/bacon-qr-code",
@@ -655,16 +656,16 @@
         },
         {
             "name": "doctrine/inflector",
-            "version": "2.0.9",
+            "version": "2.0.10",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/inflector.git",
-                "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65"
+                "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/inflector/zipball/2930cd5ef353871c821d5c43ed030d39ac8cfe65",
-                "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65",
+                "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc",
+                "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc",
                 "shasum": ""
             },
             "require": {
@@ -726,7 +727,7 @@
             ],
             "support": {
                 "issues": "https://github.com/doctrine/inflector/issues",
-                "source": "https://github.com/doctrine/inflector/tree/2.0.9"
+                "source": "https://github.com/doctrine/inflector/tree/2.0.10"
             },
             "funding": [
                 {
@@ -742,7 +743,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-15T18:05:13+00:00"
+            "time": "2024-02-18T20:23:39+00:00"
         },
         {
             "name": "endroid/qr-code",
@@ -1200,16 +1201,16 @@
         },
         {
             "name": "illuminate/collections",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/collections.git",
-                "reference": "221c1ee944cb20ed807a8a5e8668552d6ca736ff"
+                "reference": "5cedaba39e331cffd73a01cf27ea83229fa11fba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/collections/zipball/221c1ee944cb20ed807a8a5e8668552d6ca736ff",
-                "reference": "221c1ee944cb20ed807a8a5e8668552d6ca736ff",
+                "url": "https://api.github.com/repos/illuminate/collections/zipball/5cedaba39e331cffd73a01cf27ea83229fa11fba",
+                "reference": "5cedaba39e331cffd73a01cf27ea83229fa11fba",
                 "shasum": ""
             },
             "require": {
@@ -1251,11 +1252,11 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-01-22T13:55:20+00:00"
+            "time": "2024-02-09T15:56:19+00:00"
         },
         {
             "name": "illuminate/conditionable",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/conditionable.git",
@@ -1301,7 +1302,7 @@
         },
         {
             "name": "illuminate/container",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/container.git",
@@ -1352,7 +1353,7 @@
         },
         {
             "name": "illuminate/contracts",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/contracts.git",
@@ -1400,16 +1401,16 @@
         },
         {
             "name": "illuminate/database",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/database.git",
-                "reference": "a98f7b989bc11994e468bb65e3ace45671e5ebce"
+                "reference": "0b851fc41e2ea27f166768694b52ca479fc1e4c7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/database/zipball/a98f7b989bc11994e468bb65e3ace45671e5ebce",
-                "reference": "a98f7b989bc11994e468bb65e3ace45671e5ebce",
+                "url": "https://api.github.com/repos/illuminate/database/zipball/0b851fc41e2ea27f166768694b52ca479fc1e4c7",
+                "reference": "0b851fc41e2ea27f166768694b52ca479fc1e4c7",
                 "shasum": ""
             },
             "require": {
@@ -1469,11 +1470,11 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-01-30T15:46:52+00:00"
+            "time": "2024-02-13T15:01:42+00:00"
         },
         {
             "name": "illuminate/macroable",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/macroable.git",
@@ -1519,7 +1520,7 @@
         },
         {
             "name": "illuminate/pagination",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/pagination.git",
@@ -1569,16 +1570,16 @@
         },
         {
             "name": "illuminate/support",
-            "version": "v10.43.0",
+            "version": "v10.44.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/support.git",
-                "reference": "6edb9350a0d13be5cea52718280e0025d3957895"
+                "reference": "d757670dcd91b0125d0f3ab82a38cc2ad39d2acf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/support/zipball/6edb9350a0d13be5cea52718280e0025d3957895",
-                "reference": "6edb9350a0d13be5cea52718280e0025d3957895",
+                "url": "https://api.github.com/repos/illuminate/support/zipball/d757670dcd91b0125d0f3ab82a38cc2ad39d2acf",
+                "reference": "d757670dcd91b0125d0f3ab82a38cc2ad39d2acf",
                 "shasum": ""
             },
             "require": {
@@ -1636,7 +1637,7 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-01-29T14:56:21+00:00"
+            "time": "2024-02-13T14:50:39+00:00"
         },
         {
             "name": "irazasyed/telegram-bot-sdk",
@@ -1912,69 +1913,6 @@
             },
             "time": "2022-10-29T09:31:25+00:00"
         },
-        {
-            "name": "league/omnipay",
-            "version": "v3.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/thephpleague/omnipay.git",
-                "reference": "38f66a0cc043ed51d6edf7956d6439a2f263501f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/omnipay/zipball/38f66a0cc043ed51d6edf7956d6439a2f263501f",
-                "reference": "38f66a0cc043ed51d6edf7956d6439a2f263501f",
-                "shasum": ""
-            },
-            "require": {
-                "omnipay/common": "^3.1",
-                "php": "^7.2|^8.0",
-                "php-http/discovery": "^1.14",
-                "php-http/guzzle7-adapter": "^1"
-            },
-            "require-dev": {
-                "omnipay/tests": "^3|^4"
-            },
-            "type": "metapackage",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.2.x-dev"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Adrian Macneil",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Barry vd. Heuvel",
-                    "email": "[email protected]"
-                }
-            ],
-            "description": "Omnipay payment processing library",
-            "homepage": "https://omnipay.thephpleague.com/",
-            "keywords": [
-                "checkout",
-                "creditcard",
-                "omnipay",
-                "payment"
-            ],
-            "support": {
-                "issues": "https://github.com/thephpleague/omnipay/issues",
-                "source": "https://github.com/thephpleague/omnipay/tree/v3.2.1"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/barryvdh",
-                    "type": "github"
-                }
-            ],
-            "time": "2021-06-05T11:34:12+00:00"
-        },
         {
             "name": "mailgun/mailgun-php",
             "version": "v4.1.0",
@@ -2148,94 +2086,6 @@
             },
             "time": "2022-03-28T17:43:20+00:00"
         },
-        {
-            "name": "moneyphp/money",
-            "version": "v4.4.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/moneyphp/money.git",
-                "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/moneyphp/money/zipball/5e60aebf09f709dd4ea16bf85e66d65301c0d172",
-                "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172",
-                "shasum": ""
-            },
-            "require": {
-                "ext-bcmath": "*",
-                "ext-filter": "*",
-                "ext-json": "*",
-                "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
-            },
-            "require-dev": {
-                "cache/taggable-cache": "^1.1.0",
-                "doctrine/coding-standard": "^9.0",
-                "doctrine/instantiator": "^1.4.0",
-                "ext-gmp": "*",
-                "ext-intl": "*",
-                "florianv/exchanger": "^2.6.3",
-                "florianv/swap": "^4.3.0",
-                "moneyphp/crypto-currencies": "^1.0.0",
-                "moneyphp/iso-currencies": "^3.2.1",
-                "php-http/message": "^1.11.0",
-                "php-http/mock-client": "^1.4.1",
-                "phpbench/phpbench": "^1.2.5",
-                "phpunit/phpunit": "^9.5.4",
-                "psalm/plugin-phpunit": "^0.18.4",
-                "psr/cache": "^1.0.1 || ^2.0 || ^3.0",
-                "vimeo/psalm": "~5.15.0"
-            },
-            "suggest": {
-                "ext-gmp": "Calculate without integer limits",
-                "ext-intl": "Format Money objects with intl",
-                "florianv/exchanger": "Exchange rates library for PHP",
-                "florianv/swap": "Exchange rates library for PHP",
-                "psr/cache-implementation": "Used for Currency caching"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Money\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mathias Verraes",
-                    "email": "[email protected]",
-                    "homepage": "http://verraes.net"
-                },
-                {
-                    "name": "Márk Sági-Kazár",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Frederik Bosch",
-                    "email": "[email protected]"
-                }
-            ],
-            "description": "PHP implementation of Fowler's Money pattern",
-            "homepage": "http://moneyphp.org",
-            "keywords": [
-                "Value Object",
-                "money",
-                "vo"
-            ],
-            "support": {
-                "issues": "https://github.com/moneyphp/money/issues",
-                "source": "https://github.com/moneyphp/money/tree/v4.4.0"
-            },
-            "time": "2024-01-24T08:29:16+00:00"
-        },
         {
             "name": "mtdowling/jmespath.php",
             "version": "2.7.0",
@@ -2526,99 +2376,6 @@
             },
             "time": "2023-12-29T22:51:49+00:00"
         },
-        {
-            "name": "omnipay/common",
-            "version": "v3.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/thephpleague/omnipay-common.git",
-                "reference": "80545e9f4faab0efad36cc5f1e11a184dda22baf"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/80545e9f4faab0efad36cc5f1e11a184dda22baf",
-                "reference": "80545e9f4faab0efad36cc5f1e11a184dda22baf",
-                "shasum": ""
-            },
-            "require": {
-                "moneyphp/money": "^3.1|^4.0.3",
-                "php": "^7.2|^8",
-                "php-http/client-implementation": "^1",
-                "php-http/discovery": "^1.14",
-                "php-http/message": "^1.5",
-                "php-http/message-factory": "^1.1",
-                "symfony/http-foundation": "^2.1|^3|^4|^5|^6"
-            },
-            "require-dev": {
-                "omnipay/tests": "^4.1",
-                "php-http/guzzle7-adapter": "^1",
-                "php-http/mock-client": "^1",
-                "squizlabs/php_codesniffer": "^3.5"
-            },
-            "suggest": {
-                "league/omnipay": "The default Omnipay package provides a default HTTP Adapter."
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Omnipay\\Common\\": "src/Common"
-                },
-                "classmap": [
-                    "src/Omnipay.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Adrian Macneil",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Barry vd. Heuvel",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Jason Judge",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Del"
-                },
-                {
-                    "name": "Omnipay Contributors",
-                    "homepage": "https://github.com/thephpleague/omnipay-common/contributors"
-                }
-            ],
-            "description": "Common components for Omnipay payment processing library",
-            "homepage": "https://github.com/thephpleague/omnipay-common",
-            "keywords": [
-                "gateway",
-                "merchant",
-                "omnipay",
-                "pay",
-                "payment",
-                "purchase"
-            ],
-            "support": {
-                "issues": "https://github.com/thephpleague/omnipay-common/issues",
-                "source": "https://github.com/thephpleague/omnipay-common/tree/v3.2.1"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/barryvdh",
-                    "type": "github"
-                }
-            ],
-            "time": "2023-05-30T12:44:03+00:00"
-        },
         {
             "name": "openai-php/client",
             "version": "v0.8.4",
@@ -2901,68 +2658,6 @@
             },
             "time": "2023-11-30T16:49:05+00:00"
         },
-        {
-            "name": "php-http/guzzle7-adapter",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-http/guzzle7-adapter.git",
-                "reference": "fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-http/guzzle7-adapter/zipball/fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01",
-                "reference": "fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01",
-                "shasum": ""
-            },
-            "require": {
-                "guzzlehttp/guzzle": "^7.0",
-                "php": "^7.2 | ^8.0",
-                "php-http/httplug": "^2.0",
-                "psr/http-client": "^1.0"
-            },
-            "provide": {
-                "php-http/async-client-implementation": "1.0",
-                "php-http/client-implementation": "1.0",
-                "psr/http-client-implementation": "1.0"
-            },
-            "require-dev": {
-                "php-http/client-integration-tests": "^3.0",
-                "phpunit/phpunit": "^8.0|^9.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "0.2.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Http\\Adapter\\Guzzle7\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Tobias Nyholm",
-                    "email": "[email protected]"
-                }
-            ],
-            "description": "Guzzle 7 HTTP Adapter",
-            "homepage": "http://httplug.io",
-            "keywords": [
-                "Guzzle",
-                "http"
-            ],
-            "support": {
-                "issues": "https://github.com/php-http/guzzle7-adapter/issues",
-                "source": "https://github.com/php-http/guzzle7-adapter/tree/1.0.0"
-            },
-            "time": "2021-03-09T07:35:15+00:00"
-        },
         {
             "name": "php-http/httplug",
             "version": "2.4.0",
@@ -3089,61 +2784,6 @@
             },
             "time": "2023-05-17T06:43:38+00:00"
         },
-        {
-            "name": "php-http/message-factory",
-            "version": "1.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-http/message-factory.git",
-                "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-http/message-factory/zipball/4d8778e1c7d405cbb471574821c1ff5b68cc8f57",
-                "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.4",
-                "psr/http-message": "^1.0 || ^2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Http\\Message\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Márk Sági-Kazár",
-                    "email": "[email protected]"
-                }
-            ],
-            "description": "Factory interfaces for PSR-7 HTTP Message",
-            "homepage": "http://php-http.org",
-            "keywords": [
-                "factory",
-                "http",
-                "message",
-                "stream",
-                "uri"
-            ],
-            "support": {
-                "issues": "https://github.com/php-http/message-factory/issues",
-                "source": "https://github.com/php-http/message-factory/tree/1.1.0"
-            },
-            "abandoned": "psr/http-factory",
-            "time": "2023-04-14T14:16:17+00:00"
-        },
         {
             "name": "php-http/multipart-stream-builder",
             "version": "1.3.0",
@@ -4326,16 +3966,16 @@
         },
         {
             "name": "sentry/sentry",
-            "version": "4.5.0",
+            "version": "4.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/getsentry/sentry-php.git",
-                "reference": "a6e06f0b7a17e7f68e11297427da76bfe01a3ca3"
+                "reference": "30d98a460ab10f7b7032d76c62da5b1ce6c0765d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/a6e06f0b7a17e7f68e11297427da76bfe01a3ca3",
-                "reference": "a6e06f0b7a17e7f68e11297427da76bfe01a3ca3",
+                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/30d98a460ab10f7b7032d76c62da5b1ce6c0765d",
+                "reference": "30d98a460ab10f7b7032d76c62da5b1ce6c0765d",
                 "shasum": ""
             },
             "require": {
@@ -4399,7 +4039,7 @@
             ],
             "support": {
                 "issues": "https://github.com/getsentry/sentry-php/issues",
-                "source": "https://github.com/getsentry/sentry-php/tree/4.5.0"
+                "source": "https://github.com/getsentry/sentry-php/tree/4.6.0"
             },
             "funding": [
                 {
@@ -4411,7 +4051,7 @@
                     "type": "custom"
                 }
             ],
-            "time": "2024-01-29T16:16:10+00:00"
+            "time": "2024-02-13T11:32:56+00:00"
         },
         {
             "name": "slim/http",
@@ -4782,16 +4422,16 @@
         },
         {
             "name": "stripe/stripe-php",
-            "version": "v13.10.0",
+            "version": "v13.11.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/stripe/stripe-php.git",
-                "reference": "7571f6001f122db539901bda113aef7ed7af421a"
+                "reference": "d92a95bd61be5d3141d86986c3b454065f9fcc13"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/7571f6001f122db539901bda113aef7ed7af421a",
-                "reference": "7571f6001f122db539901bda113aef7ed7af421a",
+                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/d92a95bd61be5d3141d86986c3b454065f9fcc13",
+                "reference": "d92a95bd61be5d3141d86986c3b454065f9fcc13",
                 "shasum": ""
             },
             "require": {
@@ -4835,9 +4475,9 @@
             ],
             "support": {
                 "issues": "https://github.com/stripe/stripe-php/issues",
-                "source": "https://github.com/stripe/stripe-php/tree/v13.10.0"
+                "source": "https://github.com/stripe/stripe-php/tree/v13.11.0"
             },
-            "time": "2024-02-01T22:16:21+00:00"
+            "time": "2024-02-16T00:23:50+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",
@@ -5076,83 +4716,6 @@
             ],
             "time": "2023-07-30T20:28:31+00:00"
         },
-        {
-            "name": "symfony/http-foundation",
-            "version": "v6.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "5677bdf7cade4619cb17fc9e1e7b31ec392244a9"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5677bdf7cade4619cb17fc9e1e7b31ec392244a9",
-                "reference": "5677bdf7cade4619cb17fc9e1e7b31ec392244a9",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=8.1",
-                "symfony/deprecation-contracts": "^2.5|^3",
-                "symfony/polyfill-mbstring": "~1.1",
-                "symfony/polyfill-php83": "^1.27"
-            },
-            "conflict": {
-                "symfony/cache": "<6.3"
-            },
-            "require-dev": {
-                "doctrine/dbal": "^2.13.1|^3|^4",
-                "predis/predis": "^1.1|^2.0",
-                "symfony/cache": "^6.3|^7.0",
-                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
-                "symfony/expression-language": "^5.4|^6.0|^7.0",
-                "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0",
-                "symfony/mime": "^5.4|^6.0|^7.0",
-                "symfony/rate-limiter": "^5.4|^6.0|^7.0"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\HttpFoundation\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Defines an object-oriented layer for the HTTP specification",
-            "homepage": "https://symfony.com",
-            "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v6.4.3"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-01-23T14:51:35+00:00"
-        },
         {
             "name": "symfony/options-resolver",
             "version": "v7.0.0",
@@ -5771,83 +5334,6 @@
             ],
             "time": "2024-01-29T20:11:03+00:00"
         },
-        {
-            "name": "symfony/polyfill-php83",
-            "version": "v1.29.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php83.git",
-                "reference": "86fcae159633351e5fd145d1c47de6c528f8caff"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff",
-                "reference": "86fcae159633351e5fd145d1c47de6c528f8caff",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.1",
-                "symfony/polyfill-php80": "^1.14"
-            },
-            "type": "library",
-            "extra": {
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "bootstrap.php"
-                ],
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php83\\": ""
-                },
-                "classmap": [
-                    "Resources/stubs"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "support": {
-                "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-01-29T20:11:03+00:00"
-        },
         {
             "name": "symfony/service-contracts",
             "version": "v3.4.1",
@@ -9100,16 +8586,16 @@
         },
         {
             "name": "squizlabs/php_codesniffer",
-            "version": "3.8.1",
+            "version": "3.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
-                "reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
+                "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
-                "reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
+                "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
+                "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
                 "shasum": ""
             },
             "require": {
@@ -9176,7 +8662,7 @@
                     "type": "open_collective"
                 }
             ],
-            "time": "2024-01-11T20:47:48+00:00"
+            "time": "2024-02-16T15:06:51+00:00"
         },
         {
             "name": "symfony/cache",
@@ -10138,7 +9624,9 @@
     ],
     "aliases": [],
     "minimum-stability": "stable",
-    "stability-flags": [],
+    "stability-flags": {
+        "alipaysdk/openapi": 20
+    },
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {

+ 44 - 40
config/.config.example.php

@@ -1,72 +1,76 @@
 <?php
 
 //基本设置--------------------------------------------------------------------------------------------
-$_ENV['key']        = 'ChangeMe';                     //Cookie加密密钥,请务必修改此key为随机字符串
-$_ENV['pwdMethod']  = 'bcrypt';                       //密码加密 可选 bcrypt, argon2i, argon2id
-$_ENV['salt']       = '';                             //bcrypt/argon2i/argon2id 会忽略此项
+$_ENV['key']        = 'ChangeMe';            // Cookie加密密钥,请务必修改此key为随机字符串
+$_ENV['pwdMethod']  = 'bcrypt';              // 密码加密 可选 bcrypt, argon2i, argon2id
+$_ENV['salt']       = '';                    // bcrypt/argon2i/argon2id 会忽略此项
 
-$_ENV['debug']      = false;                          //debug模式开关,生产环境请保持为false
-$_ENV['appName']    = 'SSPanel-UIM';                  //站点名称
-$_ENV['baseUrl']    = 'https://example.com';          //站点地址,必须以https://开头,不要以/结尾
+$_ENV['debug']      = false;                 // debug模式开关,生产环境请保持为false
+$_ENV['appName']    = 'SSPanel-UIM';         // 站点名称
+$_ENV['baseUrl']    = 'https://example.com'; // 站点地址,必须以https://开头,不要以/结尾
 
 // WebAPI
-$_ENV['webAPI']      = true;               //是否开启WebAPI功能
-$_ENV['webAPIUrl']   = $_ENV['baseUrl'];   //WebAPI地址,如需和站点地址相同,请不要修改
-$_ENV['muKey']       = 'ChangeMe';         //WebAPI密钥,用于节点服务端与面板通信,请务必修改此key为随机字符串
-$_ENV['checkNodeIp'] = true;               //是否webapi验证节点ip
+$_ENV['webAPI']      = true;               // 是否开启WebAPI功能
+$_ENV['webAPIUrl']   = $_ENV['baseUrl'];   // WebAPI地址,如需和站点地址相同,请不要修改
+$_ENV['muKey']       = 'ChangeMe';         // WebAPI密钥,用于节点服务端与面板通信,请务必修改此key为随机字符串
+$_ENV['checkNodeIp'] = true;               // 是否webapi验证节点ip
 
 //数据库设置-------------------------------------------------------------------------------------------
-// db_host|db_socket 二选一,若设置 db_socket 则 db_host 会被忽略,不用请留空。若数据库在本机上推荐用 db_socket。
-// db_host 例: localhost(可解析的主机名), 127.0.0.1(IP 地址), 10.0.0.2:4406(含端口)
+// db_host|db_socket 二选一,若设置 db_socket 则 db_host 会被忽略,不用请留空
+// db_host 例: localhost(可解析的主机名), 127.0.0.1(IP 地址)
 // db_socket 例:/var/run/mysqld/mysqld.sock(需使用绝对地址)
 $_ENV['db_driver']    = 'mysql';
 $_ENV['db_host']      = '';
 $_ENV['db_socket']    = '';
-$_ENV['db_database']  = 'sspanel';           //数据库名
-$_ENV['db_username']  = 'root';              //数据库用户名
-$_ENV['db_password']  = 'sspanel';           //用户名对应的密码
-$_ENV['db_port']      = '3306';              //端口
+$_ENV['db_database']  = 'sspanel';           // 数据库名
+$_ENV['db_username']  = 'root';              // 数据库用户名
+$_ENV['db_password']  = 'sspanel';           // 用户密码
+$_ENV['db_port']      = '3306';              // 端口
+#读写分离相关配置
+$_ENV['enable_db_rw_split'] = false;         // 是否开启读写分离
+$_ENV['read_db_hosts']      = [''];          // 从库地址,可配置多个
+$_ENV['write_db_host']      = '';            // 主库地址
 #高级
 $_ENV['db_charset']   = 'utf8mb4';
 $_ENV['db_collation'] = 'utf8mb4_unicode_ci';
 $_ENV['db_prefix']    = '';
 
 //Redis设置-------------------------------------------------------------------------------------------
-$_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
+$_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;            //是否开启请求限制
-$_ENV['rate_limit_ip']        = 120;             //每分钟每个IP的全局请求限制
-$_ENV['rate_limit_sub']       = 30;              //每分钟每个用户的订阅链接请求限制
-$_ENV['rate_limit_webapi']    = 600;             //每分钟每个节点WebAPI密钥请求限制
-$_ENV['rate_limit_user_api']  = 60;              //每分钟每个用户的API请求限制
-$_ENV['rate_limit_admin_api'] = 60;              //每分钟每个管理员的API请求限制
+$_ENV['enable_rate_limit']    = true;         // 是否开启请求限制
+$_ENV['rate_limit_ip']        = 120;          // 每分钟每个IP的全局请求限制
+$_ENV['rate_limit_sub']       = 30;           // 每分钟每个用户的订阅链接请求限制
+$_ENV['rate_limit_webapi']    = 600;          // 每分钟每个节点WebAPI密钥请求限制
+$_ENV['rate_limit_user_api']  = 60;           // 每分钟每个用户的API请求限制
+$_ENV['rate_limit_admin_api'] = 60;           // 每分钟每个管理员的API请求限制
 
 //邮件设置--------------------------------------------------------------------------------------------
-$_ENV['mail_filter']        = 0;            //0: 关闭; 1: 白名单模式; 2; 黑名单模式;
+$_ENV['mail_filter']        = 0;            // 0: 关闭; 1: 白名单模式; 2; 黑名单模式;
 $_ENV['mail_filter_list']   = [];
 
 //已注册用户设置---------------------------------------------------------------------------------------
 #高级
-$_ENV['class_expire_reset_traffic'] = 0;            //等级到期时重置为的流量值,单位GB,小于0时不重置
-$_ENV['enable_kill']                = true;         //是否允许用户注销账户
-$_ENV['enable_change_email']        = true;         //是否允许用户更改賬戶郵箱
+$_ENV['class_expire_reset_traffic'] = 0;            // 等级到期时重置为的流量值,单位GB,小于0时不重置
+$_ENV['enable_kill']                = true;         // 是否允许用户注销账户
+$_ENV['enable_change_email']        = true;         // 是否允许用户更改賬戶郵箱
 
 #用户流量余量不足邮件提醒
-$_ENV['notify_limit_mode']          = false;         //false为关闭,per为按照百分比提醒,mb为按照固定剩余流量提醒
-$_ENV['notify_limit_value']         = 500;           //当上一项为per时,此处填写百分比;当上一项为mb时,此处填写流量
+$_ENV['notify_limit_mode']          = false;         // false为关闭,per为按照百分比提醒,mb为按照固定剩余流量提醒
+$_ENV['notify_limit_value']         = 500;           // 当上一项为per时,此处填写百分比;当上一项为mb时,此处填写流量
 
 //订阅设置---------------------------------------------------------------------------------------
-$_ENV['Subscribe']                  = true;                         //本站是否提供订阅功能
-$_ENV['subUrl']                     = $_ENV['baseUrl'];             //订阅地址,如需和站点名称相同,请不要修改
-$_ENV['sub_token_len']              = 16;                           //订阅token长度
+$_ENV['Subscribe']                  = true;              // 本站是否提供订阅功能
+$_ENV['subUrl']                     = $_ENV['baseUrl'];  // 订阅地址,如需和站点名称相同,请不要修改
+$_ENV['sub_token_len']              = 16;                // 订阅token长度
 
 //审计自动封禁设置--------------------------------------------------------------------------------------------
 $_ENV['auto_detect_ban_allow_admin'] = true;        // 管理员不受审计限制
@@ -92,7 +96,7 @@ $_ENV['locale']                   = 'zh-TW';          //默认语言
 $_ENV['jump_delay']               = 1200;             //跳转延时,单位ms
 $_ENV['keep_connect']             = false;            // 流量耗尽用户限速至 1Mbps
 
-// cdn.jsdelivr.net / fastly.jsdelivr.net / gcore.jsdelivr.net / testingcf.jsdelivr.net
+// cdn.jsdelivr.net / fastly.jsdelivr.net / testingcf.jsdelivr.net
 $_ENV['jsdelivr_url'] = 'fastly.jsdelivr.net';
 
 // https://sentry.io for production debugging

+ 26 - 9
db/migrations/2023020100-init.php

@@ -25,7 +25,10 @@ return new class() implements MigrationInterface {
                 `type` varchar(255) DEFAULT NULL COMMENT '配置值类型',
                 `default` varchar(255) DEFAULT NULL COMMENT '默认值',
                 `mark` varchar(255) DEFAULT NULL COMMENT '备注',
-                PRIMARY KEY (`id`)
+                PRIMARY KEY (`id`),
+                KEY `item` (`item`),
+                KEY `class` (`class`),
+                KEY `is_public` (`is_public`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `detect_ban_log` (
@@ -99,7 +102,8 @@ return new class() implements MigrationInterface {
                 `date` date NOT NULL DEFAULT 0 COMMENT '记录日期',
                 `usage` longtext NOT NULL DEFAULT '{}' COMMENT '流量用量' CHECK (json_valid(`usage`)),
                 PRIMARY KEY (`id`),
-                KEY `user_id` (`user_id`)
+                KEY `user_id` (`user_id`),
+                KEY `date` (`date`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `invoice` (
@@ -163,9 +167,12 @@ return new class() implements MigrationInterface {
                 `gfw_block` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT '是否被GFW封锁',
                 `password` varchar(255) NOT NULL DEFAULT '' COMMENT '后端连接密码',
                 PRIMARY KEY (`id`),
+                UNIQUE KEY `password` (`password`),
                 KEY `type` (`type`),
                 KEY `sort` (`sort`),
+                KEY `is_dynamic_rate` (`is_dynamic_rate`),
                 KEY `node_class` (`node_class`),
+                KEY `bandwidthlimit_resetday` (`bandwidthlimit_resetday`),
                 KEY `node_group` (`node_group`),
                 KEY `online` (`online`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -179,7 +186,8 @@ return new class() implements MigrationInterface {
                 `last_time` int(11) unsigned NOT NULL COMMENT '最后在线时间',
                 PRIMARY KEY (`id`),
                 UNIQUE KEY (`user_id`, `ip`),
-                KEY (`last_time`)
+                KEY `node_id` (`node_id`),
+                KEY `last_time` (`last_time`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `order` (
@@ -209,7 +217,10 @@ return new class() implements MigrationInterface {
                 `ref_get` decimal(12,2) unsigned NOT NULL DEFAULT 0 COMMENT '推荐人获得金额',
                 `invoice_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '账单ID',
                 `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
-                PRIMARY KEY (`id`)
+                PRIMARY KEY (`id`),
+                KEY `userid` (`userid`),
+                KEY `ref_by` (`ref_by`),
+                KEY `invoice_id` (`invoice_id`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `paylist` (
@@ -222,7 +233,10 @@ return new class() implements MigrationInterface {
                 `gateway` varchar(255) NOT NULL DEFAULT '' COMMENT '支付网关',
                 `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
                 PRIMARY KEY (`id`),
-                KEY `userid` (`userid`)
+                UNIQUE KEY `tradeno` (`tradeno`),
+                KEY `userid` (`userid`),
+                KEY `status` (`status`),
+                KEY `invoice_id` (`invoice_id`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `product` (
@@ -251,7 +265,8 @@ return new class() implements MigrationInterface {
                 `request_time` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '请求时间',
                 `request_user_agent` varchar(255) NOT NULL DEFAULT '' COMMENT '请求UA',
                 PRIMARY KEY (`id`),
-                KEY `user_id` (`user_id`)
+                KEY `user_id` (`user_id`),
+                KEY `type` (`type`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `ticket` (
@@ -259,12 +274,13 @@ return new class() implements MigrationInterface {
                 `title` varchar(255) NOT NULL DEFAULT '' COMMENT '工单标题',
                 `content` longtext NOT NULL DEFAULT '{}' COMMENT '工单内容' CHECK (json_valid(`content`)),
                 `userid` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
-                `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
                 `status` varchar(255) NOT NULL DEFAULT '' COMMENT '工单状态',
                 `type` varchar(255) NOT NULL DEFAULT '' COMMENT '工单类型',
+                `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
                 PRIMARY KEY (`id`),
                 KEY `userid` (`userid`),
-                KEY `status` (`status`)
+                KEY `status` (`status`),
+                KEY `type` (`type`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `user` (
@@ -318,12 +334,13 @@ return new class() implements MigrationInterface {
                 `is_inactive` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT '是否处于闲置状态',
                 `locale` varchar(16) NOT NULL DEFAULT 'zh-TW' COMMENT '显示语言',
                 PRIMARY KEY (`id`),
-                UNIQUE KEY `uuid` (`uuid`),
                 UNIQUE KEY `email` (`email`),
+                UNIQUE KEY `uuid` (`uuid`),
                 UNIQUE KEY `ga_token` (`ga_token`),
                 UNIQUE KEY `api_token` (`api_token`),
                 KEY `is_admin` (`is_admin`),
                 KEY `is_banned` (`is_banned`),
+                KEY `is_shadow_banned` (`is_shadow_banned`),
                 KEY `is_inactive` (`is_inactive`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 

+ 37 - 0
db/migrations/2024021900-add_missing_indexes.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+use App\Interfaces\MigrationInterface;
+use App\Services\DB;
+
+return new class() implements MigrationInterface {
+    public function up(): int
+    {
+        DB::getPdo()->exec('
+        ALTER TABLE config ADD KEY IF NOT EXISTS `item` (`item`);
+        ALTER TABLE config ADD KEY IF NOT EXISTS `class` (`class`);
+        ALTER TABLE config ADD KEY IF NOT EXISTS `is_public` (`is_public`);
+        ALTER TABLE hourly_usage ADD KEY IF NOT EXISTS `date` (`date`);
+        ALTER TABLE node ADD UNIQUE KEY IF NOT EXISTS `password` (`password`);
+        ALTER TABLE node ADD KEY IF NOT EXISTS `is_dynamic_rate` (`is_dynamic_rate`);
+        ALTER TABLE node ADD KEY IF NOT EXISTS `bandwidthlimit_resetday` (`bandwidthlimit_resetday`);
+        ALTER TABLE online_log ADD KEY IF NOT EXISTS `node_id` (`node_id`);
+        ALTER TABLE payback ADD KEY IF NOT EXISTS `userid` (`userid`);
+        ALTER TABLE payback ADD KEY IF NOT EXISTS `ref_by` (`ref_by`);
+        ALTER TABLE payback ADD KEY IF NOT EXISTS `invoice_id` (`invoice_id`);
+        ALTER TABLE paylist ADD UNIQUE KEY IF NOT EXISTS `tradeno` (`tradeno`);
+        ALTER TABLE paylist ADD KEY IF NOT EXISTS `status` (`status`);
+        ALTER TABLE paylist ADD KEY IF NOT EXISTS `invoice_id` (`invoice_id`);
+        ALTER TABLE subscribe_log ADD KEY IF NOT EXISTS `type` (`type`);
+        ALTER TABLE ticket ADD KEY IF NOT EXISTS `type` (`type`);
+        ALTER TABLE user ADD KEY IF NOT EXISTS `is_shadow_banned` (`is_shadow_banned`);');
+
+        return 2024021900;
+    }
+
+    public function down(): int
+    {
+        return 2024012700;
+    }
+};

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

@@ -118,7 +118,7 @@
             ],
             "columnDefs": [
                 {
-                    targets: [0],
+                    targets: [0, 6, 7],
                     orderable: false
                 },
             ],

+ 0 - 2
resources/views/tabler/gateway/f2f.tpl

@@ -12,7 +12,6 @@
 </div>
 
 <script>
-    let pid = 0;
     let f2fQrcode = $('#f2fpay-button');
 
     function f2fpay() {
@@ -27,7 +26,6 @@
             success: (data) => {
                 if (data.ret === 1) {
                     f2fQrcode.remove();
-                    pid = data.pid;
                     f2fQrcode.append('<div class="text-center"><p>手机支付宝扫描支付</p></div>');
                     new QRCode("f2f-qrcode", {
                         text: data.qrcode,

+ 1 - 0
src/Controllers/Admin/NodeController.php

@@ -318,6 +318,7 @@ final class NodeController extends BaseController
         ]);
         $new_node->name .= ' (副本)';
         $new_node->node_bandwidth = 0;
+        $new_node->password = Tools::genRandomChar(32);
 
         if (! $new_node->save()) {
             return $response->withJson([

+ 2 - 0
src/Controllers/CallbackController.php

@@ -39,8 +39,10 @@ final class CallbackController extends BaseController
 
         if (Config::obtain('enable_telegram') && $token === Config::obtain('telegram_request_token')) {
             Telegram::process($request);
+
             return $response->withStatus(204);
         }
+
         return $response->withStatus(400);
     }
 }

+ 1 - 0
src/Controllers/User/DetectLogController.php

@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace App\Controllers\User;
 
 use App\Controllers\BaseController;
+use App\Models\Config;
 use App\Models\DetectLog;
 use App\Utils\Tools;
 use Exception;

+ 20 - 0
src/Services/DB.php

@@ -29,6 +29,26 @@ final class DB extends Manager
 
     public static function getConfig(): array
     {
+        if ($_ENV['enable_db_rw_split']) {
+            return [
+                'driver' => $_ENV['db_driver'],
+                'read' => [
+                    'host' => $_ENV['read_db_hosts'],
+                ],
+                'write' => [
+                    'host' => $_ENV['write_db_host'],
+                ],
+                'sticky' => true,
+                'database' => $_ENV['db_database'],
+                'username' => $_ENV['db_username'],
+                'password' => $_ENV['db_password'],
+                'charset' => $_ENV['db_charset'],
+                'collation' => $_ENV['db_collation'],
+                'prefix' => $_ENV['db_prefix'],
+                'port' => $_ENV['db_port'],
+            ];
+        }
+
         return [
             'driver' => $_ENV['db_driver'],
             'host' => $_ENV['db_host'],

+ 139 - 0
src/Services/Gateway/AlipayF2F.php

@@ -0,0 +1,139 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Services\Gateway;
+
+use Alipay\OpenAPISDK\Api\AlipayTradeApi;
+use Alipay\OpenAPISDK\ApiException;
+use Alipay\OpenAPISDK\Model\AlipayTradePrecreateModel;
+use Alipay\OpenAPISDK\Model\AlipayTradeQueryModel;
+use Alipay\OpenAPISDK\Util\AlipayConfigUtil;
+use Alipay\OpenAPISDK\Util\AlipayLogger;
+use Alipay\OpenAPISDK\Util\Model\AlipayConfig;
+use App\Models\Config;
+use App\Models\Paylist;
+use App\Services\Auth;
+use App\Services\View;
+use Exception;
+use GuzzleHttp\Client;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+use voku\helper\AntiXSS;
+
+final class AlipayF2F extends Base
+{
+    public function __construct()
+    {
+        $this->antiXss = new AntiXSS();
+        AlipayLogger::setNeedEnableLogger(false);
+        $this->alipayConfig = new AlipayConfig();
+        $this->alipayConfig->setAppid(Config::obtain('f2f_pay_app_id'));
+        $this->alipayConfig->setPrivateKey(Config::obtain('f2f_pay_private_key'));
+        $this->alipayConfig->setAlipayPublicKey(Config::obtain('f2f_pay_public_key'));
+    }
+
+    public static function _name(): string
+    {
+        return 'f2f';
+    }
+
+    public static function _readableName(): string
+    {
+        return 'Alipay F2F';
+    }
+
+    public static function _enable(): bool
+    {
+        return self::getActiveGateway('f2f');
+    }
+
+    /**
+     * @throws Exception
+     */
+    public static function getPurchaseHTML(): string
+    {
+        return View::getSmarty()->fetch('gateway/f2f.tpl');
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
+    {
+        $price = $this->antiXss->xss_clean($request->getParam('amount'));
+        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
+        $trade_no = self::generateGuid();
+
+        if ($price <= 0) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '非法的金额',
+            ]);
+        }
+
+        $user = Auth::getUser();
+        $paylist = new Paylist();
+        $paylist->userid = $user->id;
+        $paylist->total = $price;
+        $paylist->invoice_id = $invoice_id;
+        $paylist->tradeno = $trade_no;
+        $paylist->gateway = self::_readableName();
+        $paylist->save();
+
+        $f2f_pay_notify_url = Config::obtain('f2f_pay_notify_url');
+
+        if ($f2f_pay_notify_url === '') {
+            $notifyUrl = self::getCallbackUrl();
+        } else {
+            $notifyUrl = $f2f_pay_notify_url;
+        }
+
+        $api = $this->createApi();
+        $aliRequest = new AlipayTradePrecreateModel();
+        $aliRequest->setOutTradeNo($trade_no);
+        $aliRequest->setTotalAmount($price);
+        $aliRequest->setSubject($trade_no);
+        $aliRequest->setNotifyUrl($notifyUrl);
+
+        $aliResponse = $api->precreate($aliRequest);
+        // 获取收款二维码内容
+        $qrCode = $aliResponse->getQrCode();
+
+        return $response->withJson([
+            'ret' => 1,
+            'qrcode' => $qrCode,
+            'pid' => $trade_no,
+        ]);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function notify($request, $response, $args): ResponseInterface
+    {
+        $api = $this->createApi();
+
+        $aliRequest = new AlipayTradeQueryModel();
+        $aliRequest->setOutTradeNo($_POST['out_trade_no']);
+        $aliResponse = $api->query($aliRequest);
+
+        if ($aliResponse->getTradeStatus() === 'TRADE_SUCCESS') {
+            $this->postPayment($aliResponse->getOutTradeNo());
+            // https://opendocs.alipay.com/open/194/103296#%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E7%89%B9%E6%80%A7
+            return $response->write('success');
+        }
+
+        return $response->write('failed');
+    }
+
+    private function createApi(): AlipayTradeApi
+    {
+        $alipayTradeApi = new AlipayTradeApi(new Client());
+        $alipayConfigUtil = new AlipayConfigUtil($this->alipayConfig);
+        $alipayTradeApi->setAlipayConfigUtil($alipayConfigUtil);
+
+        return $alipayTradeApi;
+    }
+}

+ 0 - 135
src/Services/Gateway/AopF2F.php

@@ -1,135 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Services\Gateway;
-
-use App\Models\Config;
-use App\Models\Paylist;
-use App\Services\Auth;
-use App\Services\View;
-use Exception;
-use Omnipay\Common\Exception\InvalidRequestException;
-use Omnipay\Common\GatewayInterface;
-use Omnipay\Omnipay;
-use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Response;
-use Slim\Http\ServerRequest;
-use voku\helper\AntiXSS;
-
-final class AopF2F extends Base
-{
-    public function __construct()
-    {
-        $this->antiXss = new AntiXSS();
-    }
-
-    public static function _name(): string
-    {
-        return 'f2f';
-    }
-
-    public static function _enable(): bool
-    {
-        return self::getActiveGateway('f2f');
-    }
-
-    public static function _readableName(): string
-    {
-        return 'Alipay F2F';
-    }
-
-    public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
-    {
-        $price = $this->antiXss->xss_clean($request->getParam('amount'));
-        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
-        $trade_no = self::generateGuid();
-
-        if ($price <= 0) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '非法的金额',
-            ]);
-        }
-
-        $user = Auth::getUser();
-        $pl = new Paylist();
-
-        $pl->userid = $user->id;
-        $pl->total = $price;
-        $pl->invoice_id = $invoice_id;
-        $pl->tradeno = $trade_no;
-        $pl->gateway = self::_readableName();
-
-        $pl->save();
-
-        $gateway = $this->createGateway();
-
-        $request = $gateway->purchase();
-        $request->setBizContent([
-            'subject' => $trade_no,
-            'out_trade_no' => $trade_no,
-            'total_amount' => $price,
-        ]);
-
-        $aliResponse = $request->send();
-
-        // 获取收款二维码内容
-        $qrCodeContent = $aliResponse->getQrCode();
-
-        return $response->withJson([
-            'ret' => 1,
-            'qrcode' => $qrCodeContent,
-            'amount' => $price,
-            'pid' => $trade_no,
-        ]);
-    }
-
-    /**
-     * @throws InvalidRequestException
-     */
-    public function notify($request, $response, $args): ResponseInterface
-    {
-        $gateway = $this->createGateway();
-        $aliRequest = $gateway->completePurchase();
-        $aliRequest->setParams($_POST);
-        $aliResponse = $aliRequest->send();
-        $pid = $aliResponse->data('out_trade_no');
-
-        if ($aliResponse->isPaid()) {
-            $this->postPayment($pid);
-            // https://opendocs.alipay.com/open/194/103296#%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E7%89%B9%E6%80%A7
-            return $response->write('success');
-        }
-
-        return $response->write('failed');
-    }
-
-    /**
-     * @throws Exception
-     */
-    public static function getPurchaseHTML(): string
-    {
-        return View::getSmarty()->fetch('gateway/f2f.tpl');
-    }
-
-    private function createGateway(): GatewayInterface
-    {
-        $configs = Config::getClass('billing');
-        $gateway = Omnipay::create('Alipay_AopF2F');
-        $gateway->setSignType('RSA2'); //RSA/RSA2
-        $gateway->setAppId($configs['f2f_pay_app_id']);
-        $gateway->setPrivateKey($configs['f2f_pay_private_key']); // 可以是路径,也可以是密钥内容
-        $gateway->setAlipayPublicKey($configs['f2f_pay_public_key']); // 可以是路径,也可以是密钥内容
-
-        if ($configs['f2f_pay_notify_url'] === '') {
-            $notifyUrl = self::getCallbackUrl();
-        } else {
-            $notifyUrl = $configs['f2f_pay_notify_url'];
-        }
-
-        $gateway->setNotifyUrl($notifyUrl);
-
-        return $gateway;
-    }
-}

+ 2 - 2
src/Services/Gateway/Base.php

@@ -49,11 +49,11 @@ abstract class Base
 
     public function getStatus(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $p = (new Paylist())->where('tradeno', $_POST['pid'])->first();
+        $paylist = (new Paylist())->where('tradeno', $_POST['pid'])->first();
 
         return $response->withJson([
             'ret' => 1,
-            'result' => $p->satatus,
+            'result' => $paylist->status,
         ]);
     }
 

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

@@ -71,7 +71,7 @@ final class StripeCard extends Base
         $pl->tradeno = $trade_no;
         $pl->save();
 
-        $exchange_amount = (new Exchange())->exchange($price, 'CNY', Config::obtain('stripe_currency'));
+        $exchange_amount = (new Exchange())->exchange((float) $price, 'CNY', Config::obtain('stripe_currency'));
 
         Stripe::setApiKey(Config::obtain('stripe_sk'));
         $session = null;

+ 17 - 10
tests/App/Services/DBTest.php

@@ -13,10 +13,11 @@ class DBTest extends TestCase
      */
     public function testGetConfig()
     {
-        // Scenario 1: All parameters are set
+        // Scenario 1: enable_db_rw_split is true
+        $_ENV['enable_db_rw_split'] = true;
         $_ENV['db_driver'] = 'mysql';
-        $_ENV['db_host'] = 'localhost';
-        $_ENV['db_socket'] = '/tmp/mysql.sock';
+        $_ENV['read_db_hosts'] = 'localhost';
+        $_ENV['write_db_host'] = 'localhost';
         $_ENV['db_database'] = 'test_db';
         $_ENV['db_username'] = 'username';
         $_ENV['db_password'] = 'password';
@@ -27,8 +28,13 @@ class DBTest extends TestCase
 
         $expected1 = [
             'driver' => 'mysql',
-            'host' => 'localhost',
-            'unix_socket' => '/tmp/mysql.sock',
+            'read' => [
+                'host' => 'localhost',
+            ],
+            'write' => [
+                'host' => 'localhost',
+            ],
+            'sticky' => true,
             'database' => 'test_db',
             'username' => 'username',
             'password' => 'password',
@@ -41,21 +47,22 @@ class DBTest extends TestCase
         $result1 = DB::getConfig();
         $this->assertEquals($expected1, $result1);
 
-        // Scenario 2: Missing parameters
-        $_ENV['db_socket'] = '';
-        $_ENV['db_port'] = '';
+        // Scenario 2: enable_db_rw_split is false
+        $_ENV['enable_db_rw_split'] = false;
+        $_ENV['db_host'] = 'localhost';
+        $_ENV['db_socket'] = '/tmp/mysql.sock';
 
         $expected2 = [
             'driver' => 'mysql',
             'host' => 'localhost',
-            'unix_socket' => '',
+            'unix_socket' => '/tmp/mysql.sock',
             'database' => 'test_db',
             'username' => 'username',
             'password' => 'password',
             'charset' => 'utf8',
             'collation' => 'utf8_unicode_ci',
             'prefix' => '',
-            'port' => '',
+            'port' => '3306',
         ];
 
         $result2 = DB::getConfig();