Explorar el Código

removed All [any] Routes & Auto-cleanning routes after sub-domian updated

兔姬桑 hace 4 años
padre
commit
9ee9bac0fd

+ 63 - 58
app/Exceptions/Handler.php

@@ -7,6 +7,7 @@ use ErrorException;
 use Exception;
 use Illuminate\Auth\AuthenticationException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Illuminate\Http\Client\ConnectionException;
 use Illuminate\Http\Request;
 use Illuminate\Session\TokenMismatchException;
 use Log;
@@ -70,65 +71,69 @@ class Handler extends ExceptionHandler
      */
     public function render($request, Throwable $exception)
     {
-        // 调试模式下直接返回错误信息
-        if (config('app.debug')) {
-            return parent::render($request, $exception);
-        }
-
-        // 捕获访问异常
-        if ($exception instanceof NotFoundHttpException) {
-            Log::info("异常请求:".$request->fullUrl().",IP:".IP::getClientIp());
-
-            if ($request->ajax()) {
-                return Response::json(['status' => 'fail', 'message' => trans('error.MissingPage')]);
+        // 调试模式下直接返回错误信息,非调试模式下渲染在返回
+        if (!config('app.debug')) {
+            switch ($exception) {
+                case $exception instanceof NotFoundHttpException: // 捕获访问异常
+                    Log::info("异常请求:".$request->fullUrl().",IP:".IP::getClientIp());
+
+                    if ($request->ajax()) {
+                        return Response::json(['status' => 'fail', 'message' => trans('error.MissingPage')]);
+                    }
+
+                    return Response::view('auth.error', ['message' => trans('error.MissingPage')], 404);
+                case $exception instanceof AuthenticationException:  // 捕获身份校验异常
+                    if ($request->ajax()) {
+                        return Response::json(['status' => 'fail', 'message' => trans('error.Unauthorized')]);
+                    }
+
+                    return Response::view('auth.error', ['message' => trans('error.Unauthorized')], 401);
+                case $exception instanceof TokenMismatchException: // 捕获CSRF异常
+                    if ($request->ajax()) {
+                        return Response::json([
+                            'status'  => 'fail',
+                            'message' => trans('error.RefreshPage').'<a href="'.route('login').'" target="_blank">'.trans('error.Refresh').'</a>',
+                        ]);
+                    }
+
+                    return Response::view('auth.error',
+                        ['message' => trans('error.RefreshPage').'<a href="'.route('login').'" target="_blank">'.trans('error.Refresh').'</a>'], 419);
+                case $exception instanceof ReflectionException:
+                    if ($request->ajax()) {
+                        return Response::json(['status' => 'fail', 'message' => trans('error.SystemError')]);
+                    }
+
+                    return Response::view('auth.error', ['message' => trans('error.SystemError')], 500);
+                case $exception instanceof ErrorException: // 捕获系统错误异常
+                    if ($request->ajax()) {
+                        return Response::json([
+                            'status'  => 'fail',
+                            'message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="'.route('log.viewer').'" target="_blank">'.trans('error.log').'</a>',
+                        ]);
+                    }
+
+                    return Response::view('auth.error',
+                        ['message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="'.route('log.viewer').'" target="_blank">'.trans('error.log').'</a>'],
+                        500);
+                case $exception instanceof ConnectionException:
+                    if ($request->ajax()) {
+                        return Response::json([
+                            'status'  => 'fail',
+                            'message' => $exception->getMessage(),
+                        ]);
+                    }
+
+                    return Response::view('auth.error', ['message' => $exception->getMessage()], 408);
+                default:
+                    if ($request->ajax()) {
+                        return Response::json([
+                            'status'  => 'fail',
+                            'message' => $exception->getMessage(),
+                        ]);
+                    }
+
+                    return Response::view('auth.error', ['message' => $exception->getMessage()]);
             }
-
-            return Response::view('auth.error', ['message' => trans('error.MissingPage')], 404);
-        }
-
-        // 捕获身份校验异常
-        if ($exception instanceof AuthenticationException) {
-            if ($request->ajax()) {
-                return Response::json(['status' => 'fail', 'message' => trans('error.Unauthorized')]);
-            }
-
-            return Response::view('auth.error', ['message' => trans('error.Unauthorized')], 401);
-        }
-
-        // 捕获CSRF异常
-        if ($exception instanceof TokenMismatchException) {
-            if ($request->ajax()) {
-                return Response::json([
-                    'status'  => 'fail',
-                    'message' => trans('error.RefreshPage').'<a href="'.route('login').'" target="_blank">'.trans('error.Refresh').'</a>',
-                ]);
-            }
-
-            return Response::view('auth.error',
-                ['message' => trans('error.RefreshPage').'<a href="'.route('login').'" target="_blank">'.trans('error.Refresh').'</a>'], 419);
-        }
-
-        // 捕获反射异常
-        if ($exception instanceof ReflectionException) {
-            if ($request->ajax()) {
-                return Response::json(['status' => 'fail', 'message' => trans('error.SystemError')]);
-            }
-
-            return Response::view('auth.error', ['message' => trans('error.SystemError')], 500);
-        }
-
-        // 捕获系统错误异常
-        if ($exception instanceof ErrorException) {
-            if ($request->ajax()) {
-                return Response::json([
-                    'status'  => 'fail',
-                    'message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="'.route('log.viewer').'" target="_blank">'.trans('error.log').'</a>',
-                ]);
-            }
-
-            return Response::view('auth.error',
-                ['message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="'.route('log.viewer').'" target="_blank">'.trans('error.log').'</a>'],
-                500);
         }
 
         return parent::render($request, $exception);

+ 1 - 19
app/Http/Controllers/Admin/UserController.php

@@ -102,7 +102,7 @@ class UserController extends Controller
 
         // 1小时内流量异常用户
         if ($flowAbnormal) {
-            $query->whereIn('id', $this->trafficAbnormal());
+            $query->whereIn('id', (new UserHourlyDataFlow)->trafficAbnormal());
         }
 
         $userList = $query->orderByDesc('id')->paginate(15)->appends($request->except('page'));
@@ -133,24 +133,6 @@ class UserController extends Controller
         ]);
     }
 
-    // 1小时内流量异常用户
-    private function trafficAbnormal(): array
-    {
-        $userTotalTrafficList = UserHourlyDataFlow::whereNodeId(0)
-            ->where('total', '>', MB * 50)
-            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
-            ->groupBy('user_id')
-            ->selectRaw("user_id, sum(total) as totalTraffic")->pluck('totalTraffic', 'user_id')
-            ->toArray(); // 只统计50M以上的记录,加快速度
-        foreach ($userTotalTrafficList as $user) {
-            if ($user->totalTraffic > sysConfig('traffic_ban_value') * GB) {
-                $result[] = $user->user_id;
-            }
-        }
-
-        return $result ?? [];
-    }
-
     // 添加账号页面
     public function create()
     {

+ 1 - 20
app/Http/Controllers/AdminController.php

@@ -50,7 +50,7 @@ class AdminController extends Controller
             [date('Y-m-d'), date('Y-m-d', strtotime("+".sysConfig('expire_days')." days"))])->count(); // 临近过期用户数
         $view['largeTrafficUserCount'] = User::whereRaw('(u + d) >= 107374182400')->where('status', '<>', -1)->count(); // 流量超过100G的用户
 
-        $view['flowAbnormalUserCount'] = count($this->trafficAbnormal());// 1小时内流量异常用户
+        $view['flowAbnormalUserCount'] = count((new UserHourlyDataFlow)->trafficAbnormal());// 1小时内流量异常用户
         $view['nodeCount'] = Node::count();
         $view['unnormalNodeCount'] = Node::whereStatus(0)->count();
         $view['flowCount'] = flowAutoShow(NodeDailyDataFlow::where('created_at', '>=', date('Y-m-d', strtotime("-30 days")))->sum('total'));
@@ -68,25 +68,6 @@ class AdminController extends Controller
         return view('admin.index', $view);
     }
 
-    // 1小时内流量异常用户
-    private function trafficAbnormal(): array
-    {
-        $userTotalTrafficList = UserHourlyDataFlow::whereNodeId(0)
-            ->where('total', '>', MB * 50)
-            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
-            ->groupBy('user_id')
-            ->selectRaw("user_id, sum(total) as totalTraffic")
-            ->pluck('totalTraffic', 'user_id')
-            ->toArray(); // 只统计50M以上的记录,加快速度
-        foreach ($userTotalTrafficList as $user) {
-            if ($user->totalTraffic > sysConfig('traffic_ban_value') * GB) {
-                $result[] = $user->user_id;
-            }
-        }
-
-        return $result ?? [];
-    }
-
     // 修改个人资料
     public function profile(Request $request)
     {

+ 3 - 2
app/Http/Controllers/Api/WebApi/BaseController.php

@@ -13,6 +13,7 @@ use App\Models\RuleGroupNode;
 use App\Models\RuleLog;
 use App\Models\User;
 use App\Models\UserDataFlowLog;
+use Arr;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Response;
@@ -70,7 +71,7 @@ class BaseController
         $inputArray = $request->all();
         $onlineCount = 0;
         foreach ($inputArray as $input) {
-            if (!array_key_exists('ip', $input) || !array_key_exists('uid', $input)) {
+            if (!Arr::has($input, ['ip', 'uid'])) {
                 return $this->returnData('上报节点在线情况失败,请检查字段');
             }
 
@@ -109,7 +110,7 @@ class BaseController
     public function setUserTraffic(Request $request, $id): JsonResponse
     {
         foreach ($request->all() as $input) {
-            if (!array_key_exists('uid', $input)) {
+            if (Arr::exists($input, 'uid')) {
                 return $this->returnData('上报用户流量日志失败,请检查字段');
             }
 

+ 3 - 0
app/Http/Controllers/UserController.php

@@ -48,6 +48,9 @@ class UserController extends Controller
     public function index()
     {
         $user = Auth::getUser();
+        if (!$user) {
+            return redirect()->route('login');
+        }
         $totalTransfer = $user->transfer_enable;
         $usedTransfer = $user->u + $user->d;
         $unusedTransfer = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;

+ 18 - 0
app/Models/UserHourlyDataFlow.php

@@ -33,4 +33,22 @@ class UserHourlyDataFlow extends Model
     {
         return $query->userHourly($uid)->where('created_at', '>=', date('Y-m-d H:55'));
     }
+
+    // 1小时内流量异常用户
+    public function trafficAbnormal(): array
+    {
+        $userTotalTrafficList = self::whereNodeId(0)
+            ->where('total', '>', MB * 50)
+            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
+            ->groupBy('user_id')
+            ->selectRaw("user_id, sum(total) as totalTraffic")->pluck('totalTraffic', 'user_id')
+            ->toArray(); // 只统计50M以上的记录,加快速度
+        foreach ($userTotalTrafficList as $user) {
+            if ($user->totalTraffic > sysConfig('traffic_ban_value') * GB) {
+                $result[] = $user->user_id;
+            }
+        }
+
+        return $result ?? [];
+    }
 }

+ 11 - 2
app/Observers/ConfigObserver.php

@@ -4,8 +4,8 @@ namespace App\Observers;
 
 use App\Components\Helpers;
 use App\Models\Config;
+use Artisan;
 use Cache;
-use Illuminate\Support\Arr;
 
 class ConfigObserver
 {
@@ -15,8 +15,17 @@ class ConfigObserver
         Cache::tags('sysConfig')->put($config->name, $config->value ?? 0);
 
         // 如果在线支付方式出现变动,改变 在线支付 设置状态
-        if (Arr::exists(['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay'], $config->name) && Cache::tags('sysConfig')->has('is_onlinePay')) {
+        if (in_array($config->name, ['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay']) && Cache::tags('sysConfig')->has('is_onlinePay')) {
             Helpers::cacheSysConfig('is_onlinePay');
         }
+
+        // 域名出现变动,更新路由设定
+        if (in_array($config->name, ['subscribe_domain', 'web_api_url', 'website_callback_url'])) {
+            if (config('app.debug')) {
+                Artisan::call('route:clear');
+            } else {
+                Artisan::call('route:cache');
+            }
+        }
     }
 }

+ 1 - 0
composer.json

@@ -10,6 +10,7 @@
   "require": {
     "php": "^7.2.5",
     "ext-json": "*",
+    "ext-mbstring": "*",
     "ext-openssl": "*",
     "fideloper/proxy": "^4.2",
     "fruitcake/laravel-cors": "^2.0",

+ 68 - 76
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "f9bb804b87de132a939ed87ee1aa87e0",
+    "content-hash": "24f73aa6d6cf6480b3991cd5070182a8",
     "packages": [
         {
             "name": "asm89/stack-cors",
@@ -1241,16 +1241,16 @@
         },
         {
             "name": "laravel-lang/lang",
-            "version": "7.0.6",
+            "version": "7.0.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Laravel-Lang/lang.git",
-                "reference": "bb0045f740dd7ac26ba97a3483b024e8c5cfdca1"
+                "reference": "7bed46cb9befef29660fb20f921a5e7b41aeaaa3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/bb0045f740dd7ac26ba97a3483b024e8c5cfdca1",
-                "reference": "bb0045f740dd7ac26ba97a3483b024e8c5cfdca1",
+                "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/7bed46cb9befef29660fb20f921a5e7b41aeaaa3",
+                "reference": "7bed46cb9befef29660fb20f921a5e7b41aeaaa3",
                 "shasum": ""
             },
             "require": {
@@ -1278,20 +1278,20 @@
                 "laravel",
                 "lpm"
             ],
-            "time": "2020-09-30T18:39:01+00:00"
+            "time": "2020-10-02T16:55:34+00:00"
         },
         {
             "name": "laravel/framework",
-            "version": "v7.28.3",
+            "version": "v7.28.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "b0942c391975972b1a54b2dc983e33a239f169a9"
+                "reference": "de187e9200948bab6975167e480950abcd5efdac"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/b0942c391975972b1a54b2dc983e33a239f169a9",
-                "reference": "b0942c391975972b1a54b2dc983e33a239f169a9",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/de187e9200948bab6975167e480950abcd5efdac",
+                "reference": "de187e9200948bab6975167e480950abcd5efdac",
                 "shasum": ""
             },
             "require": {
@@ -1436,7 +1436,7 @@
                 "framework",
                 "laravel"
             ],
-            "time": "2020-09-17T14:23:26+00:00"
+            "time": "2020-10-06T14:22:09+00:00"
         },
         {
             "name": "laravel/tinker",
@@ -2413,16 +2413,16 @@
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.40.1",
+            "version": "2.41.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "d9a76d8b7eb0f97cf3a82529393245212f40ba3b"
+                "reference": "8690b13ad4da6d54d692afea15aab30b36fee52e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d9a76d8b7eb0f97cf3a82529393245212f40ba3b",
-                "reference": "d9a76d8b7eb0f97cf3a82529393245212f40ba3b",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8690b13ad4da6d54d692afea15aab30b36fee52e",
+                "reference": "8690b13ad4da6d54d692afea15aab30b36fee52e",
                 "shasum": ""
             },
             "require": {
@@ -2498,7 +2498,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-23T08:17:37+00:00"
+            "time": "2020-10-04T09:11:05+00:00"
         },
         {
             "name": "nikic/php-parser",
@@ -3858,7 +3858,7 @@
         },
         {
             "name": "symfony/console",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
@@ -3951,7 +3951,7 @@
         },
         {
             "name": "symfony/css-selector",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
@@ -4085,16 +4085,16 @@
         },
         {
             "name": "symfony/error-handler",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/error-handler.git",
-                "reference": "d2f1d4996d5499f1261164d10080e4120001f041"
+                "reference": "5e4d8ef8d71822922d1eebd130219ae3491a5ca9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/error-handler/zipball/d2f1d4996d5499f1261164d10080e4120001f041",
-                "reference": "d2f1d4996d5499f1261164d10080e4120001f041",
+                "url": "https://api.github.com/repos/symfony/error-handler/zipball/5e4d8ef8d71822922d1eebd130219ae3491a5ca9",
+                "reference": "5e4d8ef8d71822922d1eebd130219ae3491a5ca9",
                 "shasum": ""
             },
             "require": {
@@ -4152,11 +4152,11 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-27T03:44:28+00:00"
+            "time": "2020-10-02T08:49:02+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
@@ -4322,7 +4322,7 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
@@ -4460,16 +4460,16 @@
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "6cca6b2e4b69fc5bace160d14cf1ee5f71483db4"
+                "reference": "353b42e7b4fd1c898aab09a059466c9cea74039b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6cca6b2e4b69fc5bace160d14cf1ee5f71483db4",
-                "reference": "6cca6b2e4b69fc5bace160d14cf1ee5f71483db4",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/353b42e7b4fd1c898aab09a059466c9cea74039b",
+                "reference": "353b42e7b4fd1c898aab09a059466c9cea74039b",
                 "shasum": ""
             },
             "require": {
@@ -4531,20 +4531,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-13T05:01:27+00:00"
+            "time": "2020-09-27T14:14:57+00:00"
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "17227644c3c66dcf32bdfeceff4364d090cd6756"
+                "reference": "1764b87d2f10d5c9ce6e4850fe27934116d89708"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/17227644c3c66dcf32bdfeceff4364d090cd6756",
-                "reference": "17227644c3c66dcf32bdfeceff4364d090cd6756",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1764b87d2f10d5c9ce6e4850fe27934116d89708",
+                "reference": "1764b87d2f10d5c9ce6e4850fe27934116d89708",
                 "shasum": ""
             },
             "require": {
@@ -4645,11 +4645,11 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-27T04:33:19+00:00"
+            "time": "2020-10-04T07:57:28+00:00"
         },
         {
             "name": "symfony/mime",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mime.git",
@@ -5506,7 +5506,7 @@
         },
         {
             "name": "symfony/process",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
@@ -5570,16 +5570,16 @@
         },
         {
             "name": "symfony/routing",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "d36e06eb02a55522a8eed070c1cbc3dc3c389876"
+                "reference": "720348c2ae011f8c56964c0fc3e992840cb60ccf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/d36e06eb02a55522a8eed070c1cbc3dc3c389876",
-                "reference": "d36e06eb02a55522a8eed070c1cbc3dc3c389876",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/720348c2ae011f8c56964c0fc3e992840cb60ccf",
+                "reference": "720348c2ae011f8c56964c0fc3e992840cb60ccf",
                 "shasum": ""
             },
             "require": {
@@ -5658,7 +5658,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-02T16:23:27+00:00"
+            "time": "2020-10-02T13:05:43+00:00"
         },
         {
             "name": "symfony/service-contracts",
@@ -5741,7 +5741,7 @@
         },
         {
             "name": "symfony/string",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
@@ -5826,7 +5826,7 @@
         },
         {
             "name": "symfony/translation",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
@@ -5918,16 +5918,16 @@
         },
         {
             "name": "symfony/translation-contracts",
-            "version": "v2.2.0",
+            "version": "v2.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation-contracts.git",
-                "reference": "77ce1c3627c9f39643acd9af086631f842c50c4d"
+                "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/77ce1c3627c9f39643acd9af086631f842c50c4d",
-                "reference": "77ce1c3627c9f39643acd9af086631f842c50c4d",
+                "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e2eaa60b558f26a4b0354e1bbb25636efaaad105",
+                "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105",
                 "shasum": ""
             },
             "require": {
@@ -5939,7 +5939,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2-dev"
+                    "dev-master": "2.3-dev"
                 },
                 "thanks": {
                     "name": "symfony/contracts",
@@ -5975,9 +5975,6 @@
                 "interoperability",
                 "standards"
             ],
-            "support": {
-                "source": "https://github.com/symfony/translation-contracts/tree/master"
-            },
             "funding": [
                 {
                     "url": "https://symfony.com/sponsor",
@@ -5992,11 +5989,11 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-07T11:33:47+00:00"
+            "time": "2020-09-28T13:05:58+00:00"
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
@@ -6537,16 +6534,16 @@
     "packages-dev": [
         {
             "name": "andrey-helldar/laravel-lang-publisher",
-            "version": "v6.0.2",
+            "version": "v6.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/andrey-helldar/laravel-lang-publisher.git",
-                "reference": "7efc1bef0b67962db53c05dabf2eb0f09559be3a"
+                "reference": "f139c43e615c1256f5493c6a465aef06089b451e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/andrey-helldar/laravel-lang-publisher/zipball/7efc1bef0b67962db53c05dabf2eb0f09559be3a",
-                "reference": "7efc1bef0b67962db53c05dabf2eb0f09559be3a",
+                "url": "https://api.github.com/repos/andrey-helldar/laravel-lang-publisher/zipball/f139c43e615c1256f5493c6a465aef06089b451e",
+                "reference": "f139c43e615c1256f5493c6a465aef06089b451e",
                 "shasum": ""
             },
             "require": {
@@ -6618,7 +6615,7 @@
                     "type": "custom"
                 }
             ],
-            "time": "2020-09-20T10:58:47+00:00"
+            "time": "2020-10-04T14:48:29+00:00"
         },
         {
             "name": "andrey-helldar/pretty-array",
@@ -7867,16 +7864,16 @@
         },
         {
             "name": "facade/ignition",
-            "version": "2.3.7",
+            "version": "2.3.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/facade/ignition.git",
-                "reference": "b364db8860a63c1fb58b72b9718863c21df08762"
+                "reference": "e8fed9c382cd1d02b5606688576a35619afdf82c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/facade/ignition/zipball/b364db8860a63c1fb58b72b9718863c21df08762",
-                "reference": "b364db8860a63c1fb58b72b9718863c21df08762",
+                "url": "https://api.github.com/repos/facade/ignition/zipball/e8fed9c382cd1d02b5606688576a35619afdf82c",
+                "reference": "e8fed9c382cd1d02b5606688576a35619afdf82c",
                 "shasum": ""
             },
             "require": {
@@ -7935,13 +7932,7 @@
                 "laravel",
                 "page"
             ],
-            "support": {
-                "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction",
-                "forum": "https://twitter.com/flareappio",
-                "issues": "https://github.com/facade/ignition/issues",
-                "source": "https://github.com/facade/ignition"
-            },
-            "time": "2020-09-06T19:26:27+00:00"
+            "time": "2020-10-01T23:01:14+00:00"
         },
         {
             "name": "facade/ignition-contracts",
@@ -10215,7 +10206,7 @@
         },
         {
             "name": "symfony/debug",
-            "version": "v4.4.14",
+            "version": "v4.4.15",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
@@ -10286,16 +10277,16 @@
         },
         {
             "name": "symfony/filesystem",
-            "version": "v5.1.6",
+            "version": "v5.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "f3194303d3077829dbbc1d18f50288b2a01146f2"
+                "reference": "1a8697545a8d87b9f2f6b1d32414199cc5e20aae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/f3194303d3077829dbbc1d18f50288b2a01146f2",
-                "reference": "f3194303d3077829dbbc1d18f50288b2a01146f2",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/1a8697545a8d87b9f2f6b1d32414199cc5e20aae",
+                "reference": "1a8697545a8d87b9f2f6b1d32414199cc5e20aae",
                 "shasum": ""
             },
             "require": {
@@ -10346,7 +10337,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-02T16:23:27+00:00"
+            "time": "2020-09-27T14:02:37+00:00"
         },
         {
             "name": "theseer/tokenizer",
@@ -10452,6 +10443,7 @@
     "platform": {
         "php": "^7.2.5",
         "ext-json": "*",
+        "ext-mbstring": "*",
         "ext-openssl": "*"
     },
     "platform-dev": [],

+ 323 - 322
public/install.php

@@ -14,25 +14,26 @@ define('ROOT_PATH', __DIR__.DS.'..'.DS); // 定义根目录
 define('DB_PATH', ROOT_PATH.'sql'.DS.'db.sql');// 数据库
 
 // 判断文件或目录是否有写的权限
-function is_really_writable($file) {
-	if(DIRECTORY_SEPARATOR == '/' and @ ini_get("safe_mode") == false){
-		return is_writable($file);
-	}
+function is_really_writable($file)
+{
+    if (DIRECTORY_SEPARATOR == '/' and @ ini_get("safe_mode") == false) {
+        return is_writable($file);
+    }
 
-	if(!is_file($file) or ($fp = @fopen($file, "r+")) === false){
-		return false;
-	}
+    if (!is_file($file) or ($fp = @fopen($file, "r+")) === false) {
+        return false;
+    }
 
-	fclose($fp);
+    fclose($fp);
 
-	return true;
+    return true;
 }
 
 $name = "ProxyPanel";
 
 // 检测依赖组件目录是否存在
 $checkDirs = [
-	'vendor',
+    'vendor',
 ];
 
 // 错误信息
@@ -46,330 +47,330 @@ $exampleConfigFile = ROOT_PATH.'.env.example';
 
 // 锁定的文件
 $lockFile = ROOT_PATH.'.env';
-if(is_file($lockFile)){
-	$errInfo = "如果需要重新安装,请备份数据库后手动移除 .env 文件";
-}elseif(version_compare(PHP_VERSION, '7.3.0', '<')){
-	$errInfo = "当前PHP版本(".PHP_VERSION.")过低,请使用PHP7.3.0及以上版本";
-}elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
-	$errInfo = "当前系统环境为Windows,无法进行安装";
-}elseif(!is_file($exampleConfigFile)){
-	$errInfo = "缺失标准配置文件 .env.example";
-}elseif(!extension_loaded("PDO")){
-	$errInfo = "当前PHP环境未启用PDO组件,无法进行安装";
-}elseif(!is_really_writable(ROOT_PATH)){
-	$open_basedir = ini_get('open_basedir');
-	if($open_basedir){
-		$dirArr = explode(PATH_SEPARATOR, $open_basedir);
-		if($dirArr && in_array(__DIR__, $dirArr)){
-			$errInfo = '当前服务器因配置了open_basedir,导致无法读取应用根目录';
-		}
-	}
-
-	if(!$errInfo){
-		$errInfo = '权限不足,无法写入配置文件.env';
-	}
-}else{
-	$dirArr = [];
-	foreach($checkDirs as $k => $v){
-		if(!is_dir(ROOT_PATH.$v)){
-			$errInfo = '请先在'.$name."根目录下执行<b>php composer.phar install</b> 安装依赖";
-			break;
-		}
-	}
+if (is_file($lockFile)) {
+    $errInfo = "如果需要重新安装,请备份数据库后手动移除 .env 文件";
+} elseif (version_compare(PHP_VERSION, '7.3.0', '<')) {
+    $errInfo = "当前PHP版本(".PHP_VERSION.")过低,请使用PHP7.3.0及以上版本";
+} elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+    $errInfo = "当前系统环境为Windows,无法进行安装";
+} elseif (!is_file($exampleConfigFile)) {
+    $errInfo = "缺失标准配置文件 .env.example";
+} elseif (!extension_loaded("PDO")) {
+    $errInfo = "当前PHP环境未启用PDO组件,无法进行安装";
+} elseif (!is_really_writable(ROOT_PATH)) {
+    $open_basedir = ini_get('open_basedir');
+    if ($open_basedir) {
+        $dirArr = explode(PATH_SEPARATOR, $open_basedir);
+        if ($dirArr && in_array(__DIR__, $dirArr)) {
+            $errInfo = '当前服务器因配置了open_basedir,导致无法读取应用根目录';
+        }
+    }
+
+    if (!$errInfo) {
+        $errInfo = '权限不足,无法写入配置文件.env';
+    }
+} else {
+    $dirArr = [];
+    foreach ($checkDirs as $k => $v) {
+        if (!is_dir(ROOT_PATH.$v)) {
+            $errInfo = '请先在'.$name."根目录下执行<b>php composer.phar install</b> 安装依赖";
+            break;
+        }
+    }
 }
 
 // 当前是POST请求
-if(isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST'){
-	if($errInfo){
-		echo $errInfo;
-		exit;
-	}
-
-	$err = '';
-	$APP_KEY = md5(time().mt_rand(1, 1000000));
-	$DB_HOST = isset($_POST['mysqlHost'])? trim($_POST['mysqlHost']) : '127.0.0.1';
-	$DB_PORT = isset($_POST['mysqlPort'])? trim($_POST['mysqlPort']) : 3306;
-	$hostArr = explode(':', $DB_HOST);
-	if(count($hostArr) > 1){
-		$DB_HOST = $hostArr[0];
-		$DB_PORT = $hostArr[1];
-	}
-	$DB_USERNAME = isset($_POST['mysqlUsername'])? trim($_POST['mysqlUsername']) : 'proxypanel';
-	$DB_PASSWORD = isset($_POST['mysqlPassword'])? trim($_POST['mysqlPassword']) : 'proxypanel';
-	$DB_DATABASE = isset($_POST['mysqlDatabase'])? trim($_POST['mysqlDatabase']) : 'proxypanel';
-
-	try{
-		// 检测能否读取数据库文件
-		$sql = @file_get_contents(DB_PATH);
-		if(!$sql){
-			throw new Exception("无法读取所需的".DB_PATH.",请检查是否有读权限");
-		}
-
-		$config = @file_get_contents($exampleConfigFile);
-		if(!$config){
-			throw new Exception("无法读取配置.env.example文件,请检查是否有读权限");
-		}
-
-		$pdo = new PDO("mysql:host={$DB_HOST};port={$DB_PORT}", $DB_USERNAME, $DB_PASSWORD, [
-			PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
-			PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
-		]);
-
-		// 检测是否支持innodb存储引擎
-		$pdoStatement = $pdo->query("SHOW VARIABLES LIKE 'innodb_version'");
-		$result = $pdoStatement->fetch();
-		if(!$result){
-			throw new Exception("当前数据库不支持innodb存储引擎,请开启后再重新尝试安装");
-		}
-
-		$pdo->query("CREATE DATABASE IF NOT EXISTS `{$DB_DATABASE}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
-		$pdo->query("USE `{$DB_DATABASE}`");
-		$pdo->exec($sql);
-
-		// 写入数据库配置到.env文件
-		$callback = function($matches) use ($APP_KEY, $DB_HOST, $DB_PORT, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE) {
-			$field = $matches[1];
-			$replace = ${"{$field}"};
-			return "{$matches[1]}={$replace}".PHP_EOL;
-		};
-		$config = preg_replace_callback("/(APP_KEY|DB_HOST|DB_DATABASE|DB_USERNAME|DB_PASSWORD|DB_PORT)=(.*)(\s+)/",
-			$callback, $config);
-		$result = @file_put_contents($ConfigFile, $config);
-		if(!$result){
-			throw new Exception("无法写入数据库信息到.env文件,请检查是否有写权限");
-		}
-
-		echo "success";
-	}catch(PDOException $e){
-		$err = $e->getMessage();
-	}catch(Exception $e){
-		$err = $e->getMessage();
-	}
-
-	echo $err;
-	exit;
+if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') {
+    if ($errInfo) {
+        echo $errInfo;
+        exit;
+    }
+
+    $err = '';
+    $APP_KEY = md5(time().mt_rand(1, 1000000));
+    $DB_HOST = isset($_POST['mysqlHost']) ? trim($_POST['mysqlHost']) : '127.0.0.1';
+    $DB_PORT = isset($_POST['mysqlPort']) ? trim($_POST['mysqlPort']) : 3306;
+    $hostArr = explode(':', $DB_HOST);
+    if (count($hostArr) > 1) {
+        $DB_HOST = $hostArr[0];
+        $DB_PORT = $hostArr[1];
+    }
+    $DB_USERNAME = isset($_POST['mysqlUsername']) ? trim($_POST['mysqlUsername']) : 'proxypanel';
+    $DB_PASSWORD = isset($_POST['mysqlPassword']) ? trim($_POST['mysqlPassword']) : 'proxypanel';
+    $DB_DATABASE = isset($_POST['mysqlDatabase']) ? trim($_POST['mysqlDatabase']) : 'proxypanel';
+
+    try {
+        // 检测能否读取数据库文件
+        $sql = @file_get_contents(DB_PATH);
+        if (!$sql) {
+            throw new Exception("无法读取所需的".DB_PATH.",请检查是否有读权限");
+        }
+
+        $config = @file_get_contents($exampleConfigFile);
+        if (!$config) {
+            throw new Exception("无法读取配置.env.example文件,请检查是否有读权限");
+        }
+
+        $pdo = new PDO("mysql:host={$DB_HOST};port={$DB_PORT}", $DB_USERNAME, $DB_PASSWORD, [
+            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
+            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
+        ]);
+
+        // 检测是否支持innodb存储引擎
+        $pdoStatement = $pdo->query("SHOW VARIABLES LIKE 'innodb_version'");
+        $result = $pdoStatement->fetch();
+        if (!$result) {
+            throw new Exception("当前数据库不支持innodb存储引擎,请开启后再重新尝试安装");
+        }
+
+        $pdo->query("CREATE DATABASE IF NOT EXISTS `{$DB_DATABASE}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
+        $pdo->query("USE `{$DB_DATABASE}`");
+        $pdo->exec($sql);
+
+        // 写入数据库配置到.env文件
+        $callback = function ($matches) use ($APP_KEY, $DB_HOST, $DB_PORT, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE) {
+            $field = $matches[1];
+            $replace = ${"{$field}"};
+
+            return "{$matches[1]}={$replace}".PHP_EOL;
+        };
+        $config = preg_replace_callback("/(APP_KEY|DB_HOST|DB_DATABASE|DB_USERNAME|DB_PASSWORD|DB_PORT)=(.*)(\s+)/",
+            $callback, $config);
+        $result = @file_put_contents($ConfigFile, $config);
+        if (!$result) {
+            throw new Exception("无法写入数据库信息到.env文件,请检查是否有写权限");
+        }
+
+        echo "success";
+    } catch (PDOException $e) {
+        $err = $e->getMessage();
+    } catch (Exception $e) {
+        $err = $e->getMessage();
+    }
+
+    echo $err;
+    exit;
 }
 ?>
 <!doctype html>
 <html>
 <head>
-	<meta charset="utf-8">
-	<meta http-equiv="X-UA-Compatible" content="IE=edge">
-	<title>安装<?php
-		echo $name; ?></title>
-	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
-	<meta name="renderer" content="webkit">
-
-	<style>
-		body {
-			background: #5c97bd;
-			margin: 0;
-			padding: 0;
-			line-height: 1.5;
-		}
-
-		body, input, button {
-			font-family: 'Open Sans', sans-serif;
-			font-size: 16px;
-			color: #fff;
-		}
-
-		.container {
-			max-width: 515px;
-			margin: 0 auto;
-			padding: 20px;
-			text-align: center;
-		}
-
-		a {
-			color: #fff7d0;
-			text-decoration: none;
-		}
-
-		a:hover {
-			text-decoration: underline;
-		}
-
-		h1 {
-			margin-top: 0;
-			margin-bottom: 10px;
-		}
-
-		h2 {
-			font-size: 28px;
-			font-weight: normal;
-			color: #fff;
-			margin-bottom: 0;
-		}
-
-		form {
-			margin-top: 40px;
-		}
-
-		.form-group {
-			margin-bottom: 20px;
-		}
-
-		.form-group .form-field:first-child input {
-			border-top-left-radius: 4px;
-			border-top-right-radius: 4px;
-		}
-
-		.form-group .form-field:last-child input {
-			border-bottom-left-radius: 4px;
-			border-bottom-right-radius: 4px;
-		}
-
-		.form-field input {
-			background: #6ba3c8;
-			margin: 0 0 1px;
-			border: 2px solid transparent;
-			transition: background 0.2s, border-color 0.2s, color 0.2s;
-			width: 100%;
-			padding: 15px 15px 15px 180px;
-			box-sizing: border-box;
-		}
-
-		.form-field input:focus {
-			border-color: #e8f6ff;
-			outline: none;
-		}
-
-		.form-field label {
-			float: left;
-			width: 160px;
-			text-align: right;
-			margin-right: -160px;
-			position: relative;
-			margin-top: 18px;
-			font-size: 14px;
-			pointer-events: none;
-			opacity: 0.7;
-		}
-
-		button, .btn {
-			background: #fff;
-			color: #6ba3ca;
-			border: 0;
-			font-weight: bold;
-			border-radius: 4px;
-			cursor: pointer;
-			padding: 15px 30px;
-			-webkit-appearance: none;
-		}
-
-		button[disabled] {
-			opacity: 0.5;
-		}
-
-		#error, .error, #success, .success {
-			background: #d66c6c;
-			color: #fff;
-			padding: 15px 20px;
-			border-radius: 4px;
-			margin-bottom: 20px;
-		}
-
-		#success {
-			background: #3C5675;
-		}
-
-		#error a, .error a {
-			color: white;
-			text-decoration: underline;
-		}
-	</style>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>安装<?php
+        echo $name; ?></title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
+    <meta name="renderer" content="webkit">
+
+    <style>
+        body {
+            background: #5c97bd;
+            margin: 0;
+            padding: 0;
+            line-height: 1.5;
+        }
+
+        body, input, button {
+            font-family: 'Open Sans', sans-serif;
+            font-size: 16px;
+            color: #fff;
+        }
+
+        .container {
+            max-width: 515px;
+            margin: 0 auto;
+            padding: 20px;
+            text-align: center;
+        }
+
+        a {
+            color: #fff7d0;
+            text-decoration: none;
+        }
+
+        a:hover {
+            text-decoration: underline;
+        }
+
+        h1 {
+            margin-top: 0;
+            margin-bottom: 10px;
+        }
+
+        h2 {
+            font-size: 28px;
+            font-weight: normal;
+            color: #fff;
+            margin-bottom: 0;
+        }
+
+        form {
+            margin-top: 40px;
+        }
+
+        .form-group {
+            margin-bottom: 20px;
+        }
+
+        .form-group .form-field:first-child input {
+            border-top-left-radius: 4px;
+            border-top-right-radius: 4px;
+        }
+
+        .form-group .form-field:last-child input {
+            border-bottom-left-radius: 4px;
+            border-bottom-right-radius: 4px;
+        }
+
+        .form-field input {
+            background: #6ba3c8;
+            margin: 0 0 1px;
+            border: 2px solid transparent;
+            transition: background 0.2s, border-color 0.2s, color 0.2s;
+            width: 100%;
+            padding: 15px 15px 15px 180px;
+            box-sizing: border-box;
+        }
+
+        .form-field input:focus {
+            border-color: #e8f6ff;
+            outline: none;
+        }
+
+        .form-field label {
+            float: left;
+            width: 160px;
+            text-align: right;
+            margin-right: -160px;
+            position: relative;
+            margin-top: 18px;
+            font-size: 14px;
+            pointer-events: none;
+            opacity: 0.7;
+        }
+
+        button, .btn {
+            background: #fff;
+            color: #6ba3ca;
+            border: 0;
+            font-weight: bold;
+            border-radius: 4px;
+            cursor: pointer;
+            padding: 15px 30px;
+            -webkit-appearance: none;
+        }
+
+        button[disabled] {
+            opacity: 0.5;
+        }
+
+        #error, .error, #success, .success {
+            background: #d66c6c;
+            color: #fff;
+            padding: 15px 20px;
+            border-radius: 4px;
+            margin-bottom: 20px;
+        }
+
+        #success {
+            background: #3C5675;
+        }
+
+        #error a, .error a {
+            color: white;
+            text-decoration: underline;
+        }
+    </style>
 </head>
 
 <body>
 <div class="container">
-	<h2>安装 <?php
-		echo $name; ?></h2>
-	<div>
-		<form method="post">
-			<?php
-			if($errInfo): ?>
-				<div class="error">
-					<?php
-					echo $errInfo; ?>
-				</div>
-			<?php
-			endif; ?>
-			<div id="error" style="display:none"></div>
-			<div id="success" style="display:none"></div>
-
-			<div class="form-group">
-				<div class="form-field">
-					<label>MySQL 数据库地址</label>
-					<input type="text" name="mysqlHost" value="127.0.0.1" required="">
-				</div>
-
-				<div class="form-field">
-					<label>MySQL 数据库名</label>
-					<input type="text" name="mysqlDatabase" value="proxypanel" required="">
-				</div>
-
-				<div class="form-field">
-					<label>MySQL 用户名</label>
-					<input type="text" name="mysqlUsername" value="proxypanel" required="">
-				</div>
-
-				<div class="form-field">
-					<label>MySQL 密码</label>
-					<input type="password" name="mysqlPassword">
-				</div>
-
-				<div class="form-field">
-					<label>MySQL 端口号</label>
-					<input type="number" name="mysqlPort" value="3306">
-				</div>
-			</div>
-
-			<div class="form-buttons">
-				<button type="submit" <?php
-				echo $errInfo? 'disabled' : '' ?>>安装
-				</button>
-			</div>
-		</form>
-
-		<script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
-		<script>
-			$(function () {
-
-				$('form').on('submit', function (e) {
-					e.preventDefault();
-
-					var $button = $(this).find('button').text('安装中...').prop('disabled', true);
-
-					$.post('', $(this).serialize())
-						.done(function (ret) {
-							if (ret === 'success') {
-								$('#error').hide();
-								$("#success").text("安装成功,请使用[用户名:test@test.com、密码:123456]登录").show();
-								$('<a class="btn" href="./admin/login">登录后台</a>').insertAfter($button);
-								$button.remove();
-								localStorage.setItem("fastep", "installed");
-							} else {
-								$('#error').show().text(ret);
-								$button.prop('disabled', false).text('点击安装');
-								$("html,body").animate({
-									scrollTop: 0
-								}, 500);
-							}
-						})
-						.fail(function (data) {
-							$('#error').show().text('发生错误:\n\n' + data.responseText);
-							$button.prop('disabled', false).text('点击安装');
-							$("html,body").animate({
-								scrollTop: 0
-							}, 500);
-						});
-
-					return false;
-				});
-			});
-		</script>
-	</div>
+    <h2>安装 <?php
+        echo $name; ?></h2>
+    <div>
+        <form method="post">
+            <?php
+            if ($errInfo): ?>
+                <div class="error">
+                    <?php
+                    echo $errInfo; ?>
+                </div>
+            <?php
+            endif; ?>
+            <div id="error" style="display:none"></div>
+            <div id="success" style="display:none"></div>
+
+            <div class="form-group">
+                <div class="form-field">
+                    <label>MySQL 数据库地址</label>
+                    <input type="text" name="mysqlHost" value="127.0.0.1" required="">
+                </div>
+
+                <div class="form-field">
+                    <label>MySQL 数据库名</label>
+                    <input type="text" name="mysqlDatabase" value="proxypanel" required="">
+                </div>
+
+                <div class="form-field">
+                    <label>MySQL 用户名</label>
+                    <input type="text" name="mysqlUsername" value="proxypanel" required="">
+                </div>
+
+                <div class="form-field">
+                    <label>MySQL 密码</label>
+                    <input type="password" name="mysqlPassword">
+                </div>
+
+                <div class="form-field">
+                    <label>MySQL 端口号</label>
+                    <input type="number" name="mysqlPort" value="3306">
+                </div>
+            </div>
+
+            <div class="form-buttons">
+                <button type="submit" <?php
+                echo $errInfo ? 'disabled' : '' ?>>安装
+                </button>
+            </div>
+        </form>
+
+        <script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
+        <script>
+            $(function() {
+
+                $('form').on('submit', function(e) {
+                    e.preventDefault();
+
+                    var $button = $(this).find('button').text('安装中...').prop('disabled', true);
+
+                    $.post('', $(this).serialize()).done(function(ret) {
+                        if (ret === 'success') {
+                            $('#error').hide();
+                            $('#success').text('安装成功,请使用[用户名:test@test.com、密码:123456]登录').show();
+                            $('<a class="btn" href="./admin/login">登录后台</a>').insertAfter($button);
+                            $button.remove();
+                            localStorage.setItem('fastep', 'installed');
+                        }
+                        else {
+                            $('#error').show().text(ret);
+                            $button.prop('disabled', false).text('点击安装');
+                            $('html,body').animate({
+                                scrollTop: 0,
+                            }, 500);
+                        }
+                    }).fail(function(data) {
+                        $('#error').show().text('发生错误:\n\n' + data.responseText);
+                        $button.prop('disabled', false).text('点击安装');
+                        $('html,body').animate({
+                            scrollTop: 0,
+                        }, 500);
+                    });
+
+                    return false;
+                });
+            });
+        </script>
+    </div>
 </div>
 </body>
 </html>

+ 14 - 14
routes/web.php

@@ -15,31 +15,31 @@ Route::prefix('callback')->group(function () {
 // 登录相关
 Route::middleware(['isForbidden', 'affiliate', 'isMaintenance'])->group(function () {
     Route::get('lang/{locale}', 'AuthController@switchLang')->name('lang'); // 语言切换
-    Route::any('login', 'AuthController@login')->middleware('isSecurity')->name('login'); // 登录
+    Route::match(['get', 'post'], 'login', 'AuthController@login')->middleware('isSecurity')->name('login'); // 登录
     Route::get('logout', 'AuthController@logout')->name('logout'); // 退出
-    Route::any('register', 'AuthController@register')->name('register'); // 注册
-    Route::any('reset', 'AuthController@resetPassword')->name('resetPasswd'); // 重设密码
-    Route::any('reset/{token}', 'AuthController@reset')->name('resettingPasswd'); // 重设密码
-    Route::any('activeUser', 'AuthController@activeUser')->name('active'); // 激活账号
+    Route::match(['get', 'post'], 'register', 'AuthController@register')->name('register'); // 注册
+    Route::match(['get', 'post'], 'reset', 'AuthController@resetPassword')->name('resetPasswd'); // 重设密码
+    Route::match(['get', 'post'], 'reset/{token}', 'AuthController@reset')->name('resettingPasswd'); // 重设密码
+    Route::match(['get', 'post'], 'activeUser', 'AuthController@activeUser')->name('active'); // 激活账号
     Route::get('active/{token}', 'AuthController@active')->name('activeAccount'); // 激活账号
     Route::post('send', 'AuthController@sendCode')->name('sendVerificationCode'); // 发送注册验证码
     Route::get('free', 'AuthController@free')->name('freeInvitationCode'); // 免费邀请码
     Route::get('create/string', '\Illuminate\Support\Str@random')->name('createStr'); // 生成随机密码
     Route::get('create/uuid', '\Illuminate\Support\Str@uuid')->name('createUUID'); // 生成UUID
 });
-Route::any('admin/login', 'AuthController@login')->name('admin.login')->middleware('isForbidden', 'isSecurity'); // 管理登录
+Route::match(['get', 'post'], 'admin/login', 'AuthController@login')->name('admin.login')->middleware('isForbidden', 'isSecurity'); // 管理登录
 
 // 用户相关
 Route::middleware(['isForbidden', 'isMaintenance', 'isLogin'])->group(function () {
     Route::get('/', 'UserController@index')->name('home'); // 用户首页
     Route::get('article', 'UserController@article')->name('article'); // 文章详情
     Route::post('exchangeSubscribe', 'UserController@exchangeSubscribe')->name('changeSub'); // 更换节点订阅地址
-    Route::any('nodeList', 'UserController@nodeList')->name('node'); // 节点列表
+    Route::match(['get', 'post'], 'nodeList', 'UserController@nodeList')->name('node'); // 节点列表
     Route::post('checkIn', 'UserController@checkIn')->name('checkIn'); // 签到
     Route::get('services', 'UserController@services')->name('shop'); // 商品列表
     Route::get('tickets', 'UserController@ticketList')->name('ticket'); // 工单
     Route::post('createTicket', 'UserController@createTicket')->name('openTicket'); // 快速添加工单
-    Route::any('replyTicket', 'UserController@replyTicket')->name('replyTicket'); // 回复工单
+    Route::match(['get', 'post'], 'replyTicket', 'UserController@replyTicket')->name('replyTicket'); // 回复工单
     Route::post('closeTicket', 'UserController@closeTicket')->name('closeTicket'); // 关闭工单
     Route::get('invoices', 'UserController@invoices')->name('invoice'); // 订单列表
     Route::post('closePlan', 'UserController@closePlan')->name('cancelPlan'); // 激活预支付套餐
@@ -49,7 +49,7 @@ Route::middleware(['isForbidden', 'isMaintenance', 'isLogin'])->group(function (
     Route::post('redeemCoupon', 'UserController@redeemCoupon')->name('redeemCoupon'); // 使用优惠券
     Route::get('invite', 'UserController@invite')->name('invite'); // 邀请码
     Route::post('makeInvite', 'UserController@makeInvite')->name('createInvite'); // 生成邀请码
-    Route::any('profile', 'UserController@profile')->name('profile'); // 修改个人信息
+    Route::match(['get', 'post'], 'profile', 'UserController@profile')->name('profile'); // 修改个人信息
     Route::post("switchToAdmin", "UserController@switchToAdmin")->name('switch'); // 转换成管理员的身份
     Route::post("charge", "UserController@charge")->name('recharge'); // 卡券余额充值
     Route::get("help", "UserController@help")->name('help'); // 帮助中心
@@ -70,12 +70,13 @@ Route::middleware(['isForbidden', 'isMaintenance', 'isLogin'])->group(function (
 // 管理相关
 Route::middleware(['isForbidden', 'isAdminLogin', 'isAdmin'])->prefix('admin')->name('admin.')->group(function () {
     Route::get('/', 'AdminController@index')->name('index'); // 后台首页
-    Route::any('profile', 'AdminController@profile')->name('profile'); // 修改个人信息
+    Route::match(['get', 'post'], 'profile', 'AdminController@profile')->name('profile'); // 修改个人信息
     Route::get('config', 'AdminController@config')->name('config'); // 系统设置
     Route::get('invite', 'AdminController@inviteList')->name('invite'); // 邀请码列表
     Route::post('invite', 'AdminController@makeInvite')->name('invite.create'); // 生成邀请码
     Route::get('Invite/export', 'AdminController@exportInvite')->name('invite.export'); // 导出邀请码
     Route::get('getPort', 'AdminController@getPort')->name('getPort'); // 生成端口
+    Route::get('epayInfo', 'Gateway\EPay@queryInfo')->name('test.epay');// 易支付信息
 
     Route::namespace('Admin')->group(function () {
         Route::resource('user', 'UserController')->except('show');
@@ -160,10 +161,10 @@ Route::middleware(['isForbidden', 'isAdminLogin', 'isAdmin'])->prefix('admin')->
 
         // 工具相关
         Route::prefix('tools')->name('tools.')->group(function () {
-            Route::any("decompile", "ToolsController@decompile")->name('decompile'); // SS(R)链接反解析
+            Route::match(['get', 'post'], "decompile", "ToolsController@decompile")->name('decompile'); // SS(R)链接反解析
             Route::get('download', 'ToolsController@download')->name('download'); // 下载转换过的JSON配置
-            Route::any('convert', 'ToolsController@convert')->name('convert'); // 格式转换
-            Route::any('import', 'ToolsController@import')->name('import'); // 数据导入
+            Route::match(['get', 'post'], 'convert', 'ToolsController@convert')->name('convert'); // 格式转换
+            Route::match(['get', 'post'], 'import', 'ToolsController@import')->name('import'); // 数据导入
             Route::get('analysis', 'ToolsController@analysis')->name('analysis'); // 日志分析
         });
 
@@ -179,7 +180,6 @@ Route::middleware(['isForbidden', 'isAdminLogin', 'isAdmin'])->prefix('admin')->
         Route::post('setExtend', 'SystemController@setExtend')->name('system.extend'); // 设置客服、统计代码
         Route::post('setConfig', 'SystemController@setConfig')->name('system.update'); // 设置某个配置项
         Route::post('sendTestNotification', 'SystemController@sendTestNotification')->name('test.notify'); //推送通知测试
-        Route::get('epayInfo', 'Gateway\EPay@queryInfo')->name('test.epay');// 易支付信息
     });
 
     Route::get('logs', '\Rap2hpoutre\LaravelLogViewer\LogViewerController@index')->name('log.viewer'); // 系统运行日志