diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..516299c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/runtime +/.idea +/.vscode +/vendor +*.log +.env +/tests/tmp +/tests/.phpunit.result.cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2c66292 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 walkor and contributors (see https://github.com/walkor/webman/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9538cd9 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +
+

webman

+ +基于workerman开发的超高性能PHP框架 + + +

学习

+ + + +
+ +

赞助商

+ +

特别赞助

+ + + + +

铂金赞助

+ + + +

金牌赞助

+ + +
+ + +
+

LICENSE

+The webman is open-sourced software licensed under the MIT. +
+ +
+ + diff --git a/app/controller/DepartmentController.php b/app/controller/DepartmentController.php new file mode 100644 index 0000000..2d3e33c --- /dev/null +++ b/app/controller/DepartmentController.php @@ -0,0 +1,26 @@ +departmentService->allList(); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } +} \ No newline at end of file diff --git a/app/controller/FileController.php b/app/controller/FileController.php new file mode 100644 index 0000000..3413882 --- /dev/null +++ b/app/controller/FileController.php @@ -0,0 +1,31 @@ +file('file'); + if ($file && $file->isValid()) { + $name = md5(uniqid()); + $file->move(public_path() . '/upload/' . $name . '.' . $file->getUploadExtension()); + $data = [ + 'id' => $name, + 'src' => $request->header('x-forwarded-proto') ?? 'http' . '://' . $request->host() . '/upload/' . $name . '.' . $file->getUploadExtension(), + 'fileName' => $name + ]; + return json(retData($this->result::SUCCESS, 'upload success', $data)); + } + return json(retData($this->result::ERROR, 'file not found')); + } +} \ No newline at end of file diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php new file mode 100644 index 0000000..cbfa4d2 --- /dev/null +++ b/app/controller/IndexController.php @@ -0,0 +1,30 @@ + 'webman']); + } + + public function json(Request $request) + { + + } + +} diff --git a/app/controller/MenuController.php b/app/controller/MenuController.php new file mode 100644 index 0000000..96e5613 --- /dev/null +++ b/app/controller/MenuController.php @@ -0,0 +1,39 @@ +menuService->getList(); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + + public function my(Request $request) + { + $info = $this->menuService->getList(); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + public function list(Request $request) + { + $info = $this->menuService->getList($request->uid); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } +} \ No newline at end of file diff --git a/app/controller/RoleController.php b/app/controller/RoleController.php new file mode 100644 index 0000000..2eae91a --- /dev/null +++ b/app/controller/RoleController.php @@ -0,0 +1,56 @@ +roleService->allList(); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + + /** + * User: 高军 + * Date: 2024/5/8 + * QQ: 2926804347 + * @param array $param + * @return array + * Notes: + */ + public function getList(array $param):array + { + + } + + public function save(Request $request) + { + $param = $request->post(); + $info = $this->roleService->save($param); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } +} \ No newline at end of file diff --git a/app/controller/RoleMenuController.php b/app/controller/RoleMenuController.php new file mode 100644 index 0000000..175502b --- /dev/null +++ b/app/controller/RoleMenuController.php @@ -0,0 +1,36 @@ +post(); + $info = $this->roleMenuService->save($param); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + + public function test() + { + return json(retData(0, 'ahahah')); + } +} \ No newline at end of file diff --git a/app/controller/UserController.php b/app/controller/UserController.php new file mode 100644 index 0000000..c305750 --- /dev/null +++ b/app/controller/UserController.php @@ -0,0 +1,43 @@ +post(); + if (empty($param['username']) || empty($param['password'])) return json(retData($this->result::ERROR, '账号密码不能为空')); + $info = $this->userService->login($param['username'], $param['password']); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + + public function list(Request $request) + { + $param = $request->get(); + $info = $this->userService->getList($param); + if ($info['result']) return json(retData($this->result::SUCCESS, $info['msg'], $info['data'])); + return json(retData($this->result::ERROR, $info['msg'])); + } + + public function test() + { + return json(retData(0, 'ahahah')); + } +} \ No newline at end of file diff --git a/app/functions.php b/app/functions.php new file mode 100644 index 0000000..7c30372 --- /dev/null +++ b/app/functions.php @@ -0,0 +1,14 @@ + $bool, 'msg' => $msg, 'data' => $data]; +} + +function retData(int $code, string $msg, array $data = []):array +{ + return ['code' => $code, 'msg' => $msg, 'data' => $data]; +} \ No newline at end of file diff --git a/app/middleware/AccessControl.php b/app/middleware/AccessControl.php new file mode 100644 index 0000000..6fa3822 --- /dev/null +++ b/app/middleware/AccessControl.php @@ -0,0 +1,25 @@ +method() == 'OPTIONS' ? response('') : $handler($request); + + // 给响应添加跨域相关的http头 + $response->withHeaders([ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Allow-Origin' => $request->header('origin', '*'), + 'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'), + 'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'), + ]); + + return $response; + } +} \ No newline at end of file diff --git a/app/middleware/AuthCheck.php b/app/middleware/AuthCheck.php new file mode 100644 index 0000000..65909e2 --- /dev/null +++ b/app/middleware/AuthCheck.php @@ -0,0 +1,35 @@ +controller); + $noNeedLogin = $controller->getDefaultProperties()['noNeedLogin'] ?? []; + + // 访问的方法需要登录 + if (!in_array($request->action, $noNeedLogin)) { + try { + $uid = \Tinywan\Jwt\JwtToken::getCurrentId(); + if ($uid != 0) { + $request->uid = $uid; + return $handler($request); + } + }catch (\Exception $e) { + return Response(json_encode(['code' => 0, 'msg' => $e->getMessage()], 256)); + } + }else{ + return $handler($request); + } + + // 不需要登录,请求继续向洋葱芯穿越 + return $handler($request); + } +} \ No newline at end of file diff --git a/app/middleware/StaticFile.php b/app/middleware/StaticFile.php new file mode 100644 index 0000000..eb3e33c --- /dev/null +++ b/app/middleware/StaticFile.php @@ -0,0 +1,42 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace app\middleware; + +use Webman\MiddlewareInterface; +use Webman\Http\Response; +use Webman\Http\Request; + +/** + * Class StaticFile + * @package app\middleware + */ +class StaticFile implements MiddlewareInterface +{ + public function process(Request $request, callable $next): Response + { + // Access to files beginning with. Is prohibited + if (strpos($request->path(), '/.') !== false) { + return response('

403 forbidden

', 403); + } + /** @var Response $response */ + $response = $next($request); + // Add cross domain HTTP header + /*$response->withHeaders([ + 'Access-Control-Allow-Origin' => '*', + 'Access-Control-Allow-Credentials' => 'true', + ]);*/ + return $response; + } +} diff --git a/app/model/Department.php b/app/model/Department.php new file mode 100644 index 0000000..84aab4b --- /dev/null +++ b/app/model/Department.php @@ -0,0 +1,18 @@ +field('id, name, parent_id')->select()->toArray(); + if ($info) return show(true, '获取成功', ['rows' => $info]); + return show(false, '暂无查询到数据'); + } +} \ No newline at end of file diff --git a/app/model/Menu.php b/app/model/Menu.php new file mode 100644 index 0000000..9891484 --- /dev/null +++ b/app/model/Menu.php @@ -0,0 +1,21 @@ +field('id, parent_id, title, path, name, type, icon, component')->where('delete_time', 0)->where('type', 'menu')->select()->toArray(); + if ($info) return show(true, '获取成功', $info); + return show(false, '暂无查询到的数据'); + } +} \ No newline at end of file diff --git a/app/model/Role.php b/app/model/Role.php new file mode 100644 index 0000000..178f953 --- /dev/null +++ b/app/model/Role.php @@ -0,0 +1,39 @@ +select()->toArray(); + if ($info) return show(true, '获取成功', ['rows' => $info]); + return show(false, '暂无数据'); + } + public function saveData(array $param):array + { + if (!empty($param['id'])) { + $info = $this->update($param); + }else{ + $param['create_time'] = date('Y-m-d H:i:s', time()); + $info = $this::create($param); + } + if ($info) return show(true, '保存成功'); + return show(false, '保存失败,请重试'); + } +} \ No newline at end of file diff --git a/app/model/RoleMenu.php b/app/model/RoleMenu.php new file mode 100644 index 0000000..9ed2e37 --- /dev/null +++ b/app/model/RoleMenu.php @@ -0,0 +1,25 @@ +saveAll($param); + if ($info) return show(true, '保存成功'); + return show(false, '保存失败,请重试'); + } + + public function delByRoleId(int $roleId):array + { + $info = $this->where('role_id', $roleId)->where('delete_time', 0)->update(['delete_time' => time()]); + if ($info) return show(true, '保存成功'); + return show(false, '保存失败,请重试'); + } +} \ No newline at end of file diff --git a/app/model/Test.php b/app/model/Test.php new file mode 100644 index 0000000..92d70e3 --- /dev/null +++ b/app/model/Test.php @@ -0,0 +1,29 @@ +where('delete_time', 0)->where('user_name', $userName)->find(); + if ($info) return show(true, '获取成功', $info->toArray()); + return show(false, '暂无查询到的数据'); + } + + /** + * User: 高军 + * Date: 2024/5/8 + * QQ: 2926804347 + * @param array $param + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * Notes: + */ + public function getList(array $param):array + { + $offset = ($param['page'] - 1) * $param['pageSize']; + $data = $this->limit($offset, $param['pageSize'])->select()->toArray(); + $count = $this->count(); + if ($data) return show(true, '获取成功', ['rows' => $data, 'total' => $count]); + return show(false, '暂无数据'); + } +} \ No newline at end of file diff --git a/app/service/DepartmentService.php b/app/service/DepartmentService.php new file mode 100644 index 0000000..614d808 --- /dev/null +++ b/app/service/DepartmentService.php @@ -0,0 +1,17 @@ +department->allList(); + } +} \ No newline at end of file diff --git a/app/service/MenuService.php b/app/service/MenuService.php new file mode 100644 index 0000000..7a40fea --- /dev/null +++ b/app/service/MenuService.php @@ -0,0 +1,110 @@ +menu->getList(); + if ($info['result']) { + $data = $this->package($info['data']); + $arr = $this->buildTree($data); + $tempArr['menu'] = $arr; + } + $tempArr['permissions'] = ["list.add", "list.delete", "user.edit", "user.delete"]; + $tempArr['dashboardGrid'] = ["welcome", "ver", "time", "progress", "echarts", "about"]; + $info['data'] = $tempArr; + return $info; + } + + public function myMenu(int $userId = 0):array { + $info = $this->menu->getList(); + return $info; + $arr = []; + if ($info['result']) { + $data = $this->package($info['data']); + $arr = $this->buildTree($data); + } + $info['data'] = $arr; + return $info; + } + + public function package(array $data): array + { + $arr = []; + foreach ($data as $v) { + $arr[] = [ + 'id' => $v['id'], + 'parent_id' => $v['parent_id'], + 'name' => $v['name'], + 'path' => $v['path'], + 'meta' => [ + 'title' => $v['title'], + 'icon' => $v['icon'], + 'type' => 'menu' + ], + 'component' => $v['component'] + ]; + } + return $arr; + } + + public function buildTree(array $array, int $parentId = 0): array + { + $tree = []; + foreach ($array as $element) { + if ($element['parent_id'] == $parentId) { + $children = $this->buildTree($array, $element['id']); + if ($children) { + $element['children'] = $children; + } + $tree[] = $element; + } + } + return $tree; + } + + public function add($data) + { + $data = json_decode($data, true); + foreach ($data as $k => $v) { + $arr = [ + 'parent_id' => 0, + 'name' => $v['name'], + 'path' => $v['path'], + 'title' => $v['meta']['title'], + 'icon' => $v['meta']['icon'], + 'type' => 'menu', + 'component' => $v['component'] ?? '' + ]; + $id = $this->menu->insertGetId($arr); + if (isset($v['children'])) $this->buld($id, $v['children']); + } + } + + public function buld($pid, $data) + { + foreach ($data as $v) { + $arr = [ + 'parent_id' => $pid, + 'name' => $v['name'], + 'path' => $v['path'], + 'title' => $v['meta']['title'], + 'icon' => $v['meta']['icon'] ?? '', + 'type' => 'menu', + 'component' => $v['component'] ?? '' + ]; + $id = $this->menu->insertGetId($arr); + if (isset($v['children'])) $this->buld($id, $v['children']); + } + } +} \ No newline at end of file diff --git a/app/service/RoleMenuService.php b/app/service/RoleMenuService.php new file mode 100644 index 0000000..51082c1 --- /dev/null +++ b/app/service/RoleMenuService.php @@ -0,0 +1,29 @@ + $param['role_id'], + 'menu_id' => $v, + 'create_time' => time() + ]; + } + $this->roleMenu->delByRoleId($param['role_id']); + return $this->roleMenu->saveData($arr); + } +} \ No newline at end of file diff --git a/app/service/RoleService.php b/app/service/RoleService.php new file mode 100644 index 0000000..82c5079 --- /dev/null +++ b/app/service/RoleService.php @@ -0,0 +1,22 @@ +role->allList(); + } + + public function save(array $param):array + { + return $this->role->saveData($param); + } +} \ No newline at end of file diff --git a/app/service/UserService.php b/app/service/UserService.php new file mode 100644 index 0000000..5028741 --- /dev/null +++ b/app/service/UserService.php @@ -0,0 +1,61 @@ +user->getInfoByUserName($userName); + if (!$userInfo['result']) return $userInfo; + if (!password_verify($pwd, $userInfo['data']['pass_word'])) return show(false, '用户名或密码错误'); + $tokenData = [ + 'id' => $userInfo['data']['id'], + 'name' => $userInfo['data']['nickname'], + 'email' => $userInfo['data']['email'] + ]; + $token = \Tinywan\Jwt\JwtToken::generateToken($tokenData); + unset($userInfo['data']['pass_word']); + $data = [ + 'token' => $token, + 'userInfo' => $userInfo['data'] + ]; + return show(true, '登录成功', $data); + } + + /** + * User: 高军 + * Date: 2024/5/8 + * QQ: 2926804347 + * @param array $param + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * Notes: + */ + public function getList(array $param):array + { + return $this->user->getList($param); + } +} \ No newline at end of file diff --git a/app/util/Result.php b/app/util/Result.php new file mode 100644 index 0000000..b561829 --- /dev/null +++ b/app/util/Result.php @@ -0,0 +1,8 @@ + + + + + + + + webman + + + +hello + + diff --git a/build/php8.2.micro.sfx b/build/php8.2.micro.sfx new file mode 100644 index 0000000..b78266f Binary files /dev/null and b/build/php8.2.micro.sfx differ diff --git a/build/php8.2.micro.sfx.zip b/build/php8.2.micro.sfx.zip new file mode 100644 index 0000000..e813a42 Binary files /dev/null and b/build/php8.2.micro.sfx.zip differ diff --git a/webman.bin b/build/webman.bin similarity index 100% rename from webman.bin rename to build/webman.bin diff --git a/build/webman.phar b/build/webman.phar new file mode 100644 index 0000000..623c758 Binary files /dev/null and b/build/webman.phar differ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d03c912 --- /dev/null +++ b/composer.json @@ -0,0 +1,63 @@ +{ + "name": "workerman/webman", + "type": "project", + "keywords": [ + "high performance", + "http service" + ], + "homepage": "https://www.workerman.net", + "license": "MIT", + "description": "High performance HTTP Service Framework.", + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "https://www.workerman.net", + "role": "Developer" + } + ], + "support": { + "email": "walkor@workerman.net", + "issues": "https://github.com/walkor/webman/issues", + "forum": "https://wenda.workerman.net/", + "wiki": "https://workerman.net/doc/webman", + "source": "https://github.com/walkor/webman" + }, + "require": { + "php": ">=7.2", + "workerman/webman-framework": "^1.5.0", + "monolog/monolog": "^2.0", + "webman/think-orm": "^1.1", + "psr/container": "1.1.1", + "php-di/php-di": "6", + "doctrine/annotations": "1.14", + "tinywan/jwt": "^1.9", + "webman/console": "^1.3", + "vlucas/phpdotenv": "^5.6" + }, + "suggest": { + "ext-event": "For better performance. " + }, + "autoload": { + "psr-4": { + "": "./", + "app\\": "./app", + "App\\": "./app", + "app\\View\\Components\\": "./app/view/components" + }, + "files": [ + "./support/helpers.php" + ] + }, + "scripts": { + "post-package-install": [ + "support\\Plugin::install" + ], + "post-package-update": [ + "support\\Plugin::install" + ], + "pre-package-uninstall": [ + "support\\Plugin::uninstall" + ] + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..5212c17 --- /dev/null +++ b/composer.lock @@ -0,0 +1,2383 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "f35e502bc0a69800b908c2e9210d28a1", + "packages": [ + { + "name": "doctrine/annotations", + "version": "1.14.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "3587ab58646bc515b2e03bbd3cfcd3682e8df5bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/3587ab58646bc515b2e03bbd3cfcd3682e8df5bf", + "reference": "3587ab58646bc515b2e03bbd3cfcd3682e8df5bf", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1 || ^2", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "vimeo/psalm": "^4.10" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.14.0" + }, + "time": "2022-12-11T18:25:48+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + }, + "time": "2024-01-30T19:34:25+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "doctrine/lexer", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/2.1.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:35:39+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v6.10.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff", + "shasum": "" + }, + "require": { + "php": "^7.4||^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5||^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^1.0||^2.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.10.0" + }, + "time": "2023-12-01T16:26:39+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.2", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2023-11-12T22:16:48+00:00" + }, + { + "name": "jeremeamia/superclosure", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.2|^2.0|^3.0|^4.0", + "php": ">=5.4", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", + "homepage": "https://github.com/jeremeamia/super_closure", + "keywords": [ + "closure", + "function", + "lambda", + "parser", + "serializable", + "serialize", + "tokenizer" + ], + "support": { + "issues": "https://github.com/jeremeamia/super_closure/issues", + "source": "https://github.com/jeremeamia/super_closure/tree/master" + }, + "abandoned": "opis/closure", + "time": "2018-03-21T22:21:57+00:00" + }, + { + "name": "monolog/monolog", + "version": "2.9.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.38 || ^9.6.19", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.9.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-04-12T20:52:51+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v3.1.5" + }, + "time": "2018-02-28T20:30:58+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2023-09-08T09:24:21+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "4773f7644b0c98ebfc22a1368e519ab5ac2e076c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/4773f7644b0c98ebfc22a1368e519ab5ac2e076c", + "reference": "4773f7644b0c98ebfc22a1368e519ab5ac2e076c", + "shasum": "" + }, + "require": { + "jeremeamia/superclosure": "^2.0", + "nikic/php-parser": "^2.0|^3.0", + "php": ">=7.0.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "~1.0", + "ocramius/proxy-manager": "~2.0.2", + "phpunit/phpunit": "~6.4" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "http://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/master" + }, + "time": "2018-02-20T07:27:46+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "support": { + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" + }, + "time": "2020-10-12T12:39:22+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.2", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2023-11-12T21:59:55+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "symfony/console", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c981e0e9380ce9f146416bde3150c79197ce9986" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986", + "reference": "c981e0e9380ce9f146416bde3150c79197ce9986", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.0.7" + }, + "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-04-18T09:29:19+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.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-04-18T09:32:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/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/polyfill-intl-grapheme", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/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/polyfill-intl-normalizer", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/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/polyfill-mbstring", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/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/polyfill-php56", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.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": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/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.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.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-04-18T09:32:20+00:00" + }, + { + "name": "symfony/string", + "version": "v7.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b", + "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.0.4" + }, + "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-02-01T13:17:36+00:00" + }, + { + "name": "tinywan/jwt", + "version": "v1.9.1", + "source": { + "type": "git", + "url": "https://github.com/Tinywan/webman-jwt.git", + "reference": "9e637852e870394b064068c646074dabeca0c2a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Tinywan/webman-jwt/zipball/9e637852e870394b064068c646074dabeca0c2a9", + "reference": "9e637852e870394b064068c646074dabeca0c2a9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "firebase/php-jwt": "^6.8", + "php": "^7.1||^8.0", + "workerman/webman-framework": "^1.2.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.6", + "illuminate/database": "^8.83", + "mockery/mockery": "^1.5", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.0", + "topthink/think-orm": "^2.0", + "vimeo/psalm": "^4.22", + "workerman/webman": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tinywan\\Jwt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "JSON Web Token (JWT) for webman plugin", + "support": { + "issues": "https://github.com/Tinywan/webman-jwt/issues", + "source": "https://github.com/Tinywan/webman-jwt/tree/v1.9.1" + }, + "time": "2024-01-10T07:31:44+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/helper.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" + }, + "time": "2021-12-15T04:27:55+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v3.0.14", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "7b0b8ea6ca5e020217f6ba7ae34d547e148a675b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/7b0b8ea6ca5e020217f6ba7ae34d547e148a675b", + "reference": "7b0b8ea6ca5e020217f6ba7ae34d547e148a675b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=8.0.0", + "psr/log": ">=1.0", + "psr/simple-cache": ">=1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^8|^9.5|^10" + }, + "type": "library", + "autoload": { + "files": [ + "stubs/load_stubs.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the PHP Database&ORM Framework", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v3.0.14" + }, + "time": "2023-09-24T13:15:07+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.2", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2023-11-12T22:43:29+00:00" + }, + { + "name": "webman/console", + "version": "v1.3.6", + "source": { + "type": "git", + "url": "https://github.com/webman-php/console.git", + "reference": "0096680820014b12c1f98129a9005e5f960ab292" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webman-php/console/zipball/0096680820014b12c1f98129a9005e5f960ab292", + "reference": "0096680820014b12c1f98129a9005e5f960ab292", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^2.0", + "symfony/console": ">=5.0" + }, + "require-dev": { + "workerman/webman": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webman\\Console\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "http://www.workerman.net", + "role": "Developer" + } + ], + "description": "Webman console", + "homepage": "http://www.workerman.net", + "keywords": [ + "webman console" + ], + "support": { + "email": "walkor@workerman.net", + "forum": "http://www.workerman.net/questions", + "issues": "https://github.com/webman-php/console/issues", + "source": "https://github.com/webman-php/console", + "wiki": "http://www.workerman.net/doc/webman" + }, + "time": "2024-04-10T07:21:40+00:00" + }, + { + "name": "webman/think-orm", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/webman-php/think-orm.git", + "reference": "9f1e525c5c4b5a2e1eee6a4f82ef5d23c69139a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webman-php/think-orm/zipball/9f1e525c5c4b5a2e1eee6a4f82ef5d23c69139a2", + "reference": "9f1e525c5c4b5a2e1eee6a4f82ef5d23c69139a2", + "shasum": "" + }, + "require": { + "topthink/think-orm": "^2.0.53 || ^3.0.0", + "workerman/webman-framework": "^1.2.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webman\\ThinkOrm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "support": { + "issues": "https://github.com/webman-php/think-orm/issues", + "source": "https://github.com/webman-php/think-orm/tree/v1.1.1" + }, + "time": "2023-04-23T14:40:18+00:00" + }, + { + "name": "workerman/webman-framework", + "version": "v1.5.16", + "source": { + "type": "git", + "url": "https://github.com/walkor/webman-framework.git", + "reference": "84335520a340ee60adf7cf17aeb0edb9536c24e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/walkor/webman-framework/zipball/84335520a340ee60adf7cf17aeb0edb9536c24e8", + "reference": "84335520a340ee60adf7cf17aeb0edb9536c24e8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": ">=7.2", + "psr/container": ">=1.0", + "workerman/workerman": "^4.0.4 || ^5.0.0" + }, + "suggest": { + "ext-event": "For better performance. " + }, + "type": "library", + "autoload": { + "psr-4": { + "Webman\\": "./src", + "Support\\": "./src/support", + "support\\": "./src/support", + "Support\\View\\": "./src/support/view", + "Support\\Bootstrap\\": "./src/support/bootstrap", + "Support\\Exception\\": "./src/support/exception" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "https://www.workerman.net", + "role": "Developer" + } + ], + "description": "High performance HTTP Service Framework.", + "homepage": "https://www.workerman.net", + "keywords": [ + "High Performance", + "http service" + ], + "support": { + "email": "walkor@workerman.net", + "forum": "https://wenda.workerman.net/", + "issues": "https://github.com/walkor/webman/issues", + "source": "https://github.com/walkor/webman-framework", + "wiki": "https://doc.workerman.net/" + }, + "time": "2024-01-15T12:11:49+00:00" + }, + { + "name": "workerman/workerman", + "version": "v4.1.15", + "source": { + "type": "git", + "url": "https://github.com/walkor/workerman.git", + "reference": "afc8242fc769ab7cf22eb4ac22b97cb59d465e4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/walkor/workerman/zipball/afc8242fc769ab7cf22eb4ac22b97cb59d465e4e", + "reference": "afc8242fc769ab7cf22eb4ac22b97cb59d465e4e", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "suggest": { + "ext-event": "For better performance. " + }, + "type": "library", + "autoload": { + "psr-4": { + "Workerman\\": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "http://www.workerman.net", + "role": "Developer" + } + ], + "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", + "homepage": "http://www.workerman.net", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "email": "walkor@workerman.net", + "forum": "http://wenda.workerman.net/", + "issues": "https://github.com/walkor/workerman/issues", + "source": "https://github.com/walkor/workerman", + "wiki": "http://doc.workerman.net/" + }, + "funding": [ + { + "url": "https://opencollective.com/workerman", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/walkor", + "type": "patreon" + } + ], + "time": "2024-02-19T02:10:39+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.2" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..f26e358 --- /dev/null +++ b/config/app.php @@ -0,0 +1,26 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\Request; + +return [ + 'debug' => true, + 'error_reporting' => E_ALL, + 'default_timezone' => 'Asia/Shanghai', + 'request_class' => Request::class, + 'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public', + 'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime', + 'controller_suffix' => 'Controller', + 'controller_reuse' => false, +]; diff --git a/config/autoload.php b/config/autoload.php new file mode 100644 index 0000000..69a8135 --- /dev/null +++ b/config/autoload.php @@ -0,0 +1,21 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'files' => [ + base_path() . '/app/functions.php', + base_path() . '/support/Request.php', + base_path() . '/support/Response.php', + ] +]; diff --git a/config/bootstrap.php b/config/bootstrap.php new file mode 100644 index 0000000..3257ec5 --- /dev/null +++ b/config/bootstrap.php @@ -0,0 +1,19 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + support\bootstrap\Session::class, + support\bootstrap\LaravelDb::class, + Webman\ThinkOrm\ThinkOrm::class, +]; diff --git a/config/container.php b/config/container.php new file mode 100644 index 0000000..3ce9227 --- /dev/null +++ b/config/container.php @@ -0,0 +1,19 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +$builder = new \DI\ContainerBuilder(); +$builder->addDefinitions(config('dependence', [])); +$builder->useAutowiring(true); +$builder->useAnnotations(true); +return $builder->build(); +//return new Webman\Container; \ No newline at end of file diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..7dc463a --- /dev/null +++ b/config/database.php @@ -0,0 +1,15 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return []; diff --git a/config/dependence.php b/config/dependence.php new file mode 100644 index 0000000..8e964ed --- /dev/null +++ b/config/dependence.php @@ -0,0 +1,15 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return []; \ No newline at end of file diff --git a/config/exception.php b/config/exception.php new file mode 100644 index 0000000..f2aede3 --- /dev/null +++ b/config/exception.php @@ -0,0 +1,17 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + '' => support\exception\Handler::class, +]; \ No newline at end of file diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..7f05de5 --- /dev/null +++ b/config/log.php @@ -0,0 +1,32 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'default' => [ + 'handlers' => [ + [ + 'class' => Monolog\Handler\RotatingFileHandler::class, + 'constructor' => [ + runtime_path() . '/logs/webman.log', + 7, //$maxFiles + Monolog\Logger::DEBUG, + ], + 'formatter' => [ + 'class' => Monolog\Formatter\LineFormatter::class, + 'constructor' => [null, 'Y-m-d H:i:s', true], + ], + ] + ], + ], +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..5186454 --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,20 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + '' => [ + \app\middleware\AccessControl::class, + \app\middleware\AuthCheck::class + ] +]; \ No newline at end of file diff --git a/config/plugin/tinywan/jwt/app.php b/config/plugin/tinywan/jwt/app.php new file mode 100644 index 0000000..9def507 --- /dev/null +++ b/config/plugin/tinywan/jwt/app.php @@ -0,0 +1,83 @@ + true, + 'jwt' => [ + /** 算法类型 HS256、HS384、HS512、RS256、RS384、RS512、ES256、ES384、Ed25519 */ + 'algorithms' => 'HS256', + + /** access令牌秘钥 */ + 'access_secret_key' => '2022d3d3LmJq', + + /** access令牌过期时间,单位:秒。默认 2 小时 */ + 'access_exp' => 7200, + + /** refresh令牌秘钥 */ + 'refresh_secret_key' => '2022KTxigxc9o50c', + + /** refresh令牌过期时间,单位:秒。默认 7 天 */ + 'refresh_exp' => 604800, + + /** refresh 令牌是否禁用,默认不禁用 false */ + 'refresh_disable' => false, + + /** 令牌签发者 */ + 'iss' => 'webman.tinywan.cn', + + /** 某个时间点后才能访问,单位秒。(如:30 表示当前时间30秒后才能使用) */ + 'nbf' => 0, + + /** 时钟偏差冗余时间,单位秒。建议这个余地应该不大于几分钟 */ + 'leeway' => 60, + + /** 是否允许单设备登录,默认不允许 false */ + 'is_single_device' => false, + + /** 缓存令牌时间,单位:秒。默认 7 天 */ + 'cache_token_ttl' => 604800, + + /** 缓存令牌前缀,默认 JWT:TOKEN: */ + 'cache_token_pre' => 'JWT:TOKEN:', + + /** 缓存刷新令牌前缀,默认 JWT:REFRESH_TOKEN: */ + 'cache_refresh_token_pre' => 'JWT:REFRESH_TOKEN:', + + /** 用户信息模型 */ + 'user_model' => function ($uid) { + return []; + }, + + /** 是否支持 get 请求获取令牌 */ + 'is_support_get_token' => false, + /** GET 请求获取令牌请求key */ + 'is_support_get_token_key' => 'authorization', + + /** access令牌私钥 */ + 'access_private_key' => << << << << true, + + 'build_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build', + + 'phar_filename' => 'webman.phar', + + 'bin_filename' => 'webman.bin', + + 'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL. + + 'private_key_file' => '', // The file path for certificate or OpenSSL private key file. + + 'exclude_pattern' => '#^(?!.*(composer.json|/.github/|/.idea/|/.git/|/.setting/|/runtime/|/vendor-bin/|/build/|/vendor/webman/admin/))(.*)$#', + + 'exclude_files' => [ + '.env', 'LICENSE', 'composer.json', 'composer.lock', 'start.php', 'webman.phar', 'webman.bin' + ], + + 'custom_ini' => ' +memory_limit = 256M + ', +]; diff --git a/config/process.php b/config/process.php new file mode 100644 index 0000000..f94d27f --- /dev/null +++ b/config/process.php @@ -0,0 +1,42 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +global $argv; + +return [ + // File update detection and automatic reload + 'monitor' => [ + 'handler' => process\Monitor::class, + 'reloadable' => false, + 'constructor' => [ + // Monitor these directories + 'monitorDir' => array_merge([ + app_path(), + config_path(), + base_path() . '/process', + base_path() . '/support', + base_path() . '/resource', + base_path() . '/.env', + ], glob(base_path() . '/plugin/*/app'), glob(base_path() . '/plugin/*/config'), glob(base_path() . '/plugin/*/api')), + // Files with these suffixes will be monitored + 'monitorExtensions' => [ + 'php', 'html', 'htm', 'env' + ], + 'options' => [ + 'enable_file_monitor' => !in_array('-d', $argv) && DIRECTORY_SEPARATOR === '/', + 'enable_memory_monitor' => DIRECTORY_SEPARATOR === '/', + ] + ] + ] +]; diff --git a/config/redis.php b/config/redis.php new file mode 100644 index 0000000..2f9757a --- /dev/null +++ b/config/redis.php @@ -0,0 +1,22 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'default' => [ + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'database' => 0, + ], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..a5064fc --- /dev/null +++ b/config/route.php @@ -0,0 +1,21 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use Webman\Route; + + + + + + diff --git a/config/server.php b/config/server.php new file mode 100644 index 0000000..84ea0ef --- /dev/null +++ b/config/server.php @@ -0,0 +1,31 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'listen' => 'http://0.0.0.0:8787', + 'transport' => 'tcp', + 'context' => [], + 'name' => 'webman', + 'count' => cpu_count() * 4, + 'user' => '', + 'group' => '', + 'reusePort' => false, + 'event_loop' => '', + 'stop_timeout' => 2, + 'pid_file' => runtime_path() . '/webman.pid', + 'status_file' => runtime_path() . '/webman.status', + 'stdout_file' => runtime_path() . '/logs/stdout.log', + 'log_file' => runtime_path() . '/logs/workerman.log', + 'max_package_size' => 10 * 1024 * 1024 +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..043f8c4 --- /dev/null +++ b/config/session.php @@ -0,0 +1,65 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use Webman\Session\FileSessionHandler; +use Webman\Session\RedisSessionHandler; +use Webman\Session\RedisClusterSessionHandler; + +return [ + + 'type' => 'file', // or redis or redis_cluster + + 'handler' => FileSessionHandler::class, + + 'config' => [ + 'file' => [ + 'save_path' => runtime_path() . '/sessions', + ], + 'redis' => [ + 'host' => '127.0.0.1', + 'port' => 6379, + 'auth' => '', + 'timeout' => 2, + 'database' => '', + 'prefix' => 'redis_session_', + ], + 'redis_cluster' => [ + 'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'], + 'timeout' => 2, + 'auth' => '', + 'prefix' => 'redis_session_', + ] + ], + + 'session_name' => 'PHPSID', + + 'auto_update_timestamp' => false, + + 'lifetime' => 7*24*60*60, + + 'cookie_lifetime' => 365*24*60*60, + + 'cookie_path' => '/', + + 'domain' => '', + + 'http_only' => true, + + 'secure' => false, + + 'same_site' => '', + + 'gc_probability' => [1, 1000], + +]; diff --git a/config/static.php b/config/static.php new file mode 100644 index 0000000..6313679 --- /dev/null +++ b/config/static.php @@ -0,0 +1,23 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * Static file settings + */ +return [ + 'enable' => true, + 'middleware' => [ // Static file Middleware + //app\middleware\StaticFile::class, + ], +]; \ No newline at end of file diff --git a/config/thinkorm.php b/config/thinkorm.php new file mode 100644 index 0000000..f66d4c8 --- /dev/null +++ b/config/thinkorm.php @@ -0,0 +1,36 @@ + 'mysql', + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => 'mysql', + // 服务器地址 + 'hostname' => getenv('DB_HOST'), + // 数据库名 + 'database' => getenv('DB_NAME'), + // 数据库用户名 + 'username' => getenv('DB_USER'), + // 数据库密码 + 'password' => getenv('DB_PASSWORD'), + // 数据库连接端口 + 'hostport' => getenv('DB_PORT'), + // 数据库连接参数 + 'params' => [ + // 连接超时3秒 + \PDO::ATTR_TIMEOUT => 3, + ], + // 数据库编码默认采用utf8 + 'charset' => 'utf8', + // 数据库表前缀 + 'prefix' => '', + // 断线重连 + 'break_reconnect' => true, + // 关闭SQL监听日志 + 'trigger_sql' => false, + // 自定义分页类 + 'bootstrap' => '' + ], + ], +]; diff --git a/config/translation.php b/config/translation.php new file mode 100644 index 0000000..96589b2 --- /dev/null +++ b/config/translation.php @@ -0,0 +1,25 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * Multilingual configuration + */ +return [ + // Default language + 'locale' => 'zh_CN', + // Fallback language + 'fallback_locale' => ['zh_CN', 'en'], + // Folder where language files are stored + 'path' => base_path() . '/resource/translations', +]; \ No newline at end of file diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..e3a7b85 --- /dev/null +++ b/config/view.php @@ -0,0 +1,22 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\view\Raw; +use support\view\Twig; +use support\view\Blade; +use support\view\ThinkPHP; + +return [ + 'handler' => Raw::class +]; diff --git a/menu.json b/menu.json new file mode 100644 index 0000000..2256d5b --- /dev/null +++ b/menu.json @@ -0,0 +1,803 @@ +[ + { + "name": "home", + "path": "/home", + "meta": { + "title": "首页", + "icon": "el-icon-eleme-filled", + "type": "menu" + }, + "children": [ + { + "name": "dashboard", + "path": "/dashboard", + "meta": { + "title": "控制台", + "icon": "el-icon-menu", + "affix": true + }, + "component": "home" + }, + { + "name": "userCenter", + "path": "/usercenter", + "meta": { + "title": "帐号信息", + "icon": "el-icon-user", + "tag": "NEW" + }, + "component": "userCenter" + } + ] + }, + { + "name": "vab", + "path": "/vab", + "meta": { + "title": "组件", + "icon": "el-icon-takeaway-box", + "type": "menu" + }, + "children": [ + { + "path": "/vab/mini", + "name": "minivab", + "meta": { + "title": "原子组件", + "icon": "el-icon-magic-stick", + "type": "menu" + }, + "component": "vab/mini" + }, + { + "path": "/vab/iconfont", + "name": "iconfont", + "meta": { + "title": "扩展图标", + "icon": "el-icon-orange", + "type": "menu" + }, + "component": "vab/iconfont" + }, + { + "path": "/vab/data", + "name": "vabdata", + "meta": { + "title": "Data 数据展示", + "icon": "el-icon-histogram", + "type": "menu" + }, + "children": [ + { + "path": "/vab/chart", + "name": "chart", + "meta": { + "title": "图表 Echarts", + "type": "menu" + }, + "component": "vab/chart" + }, + { + "path": "/vab/statistic", + "name": "statistic", + "meta": { + "title": "统计数值", + "type": "menu" + }, + "component": "vab/statistic" + }, + { + "path": "/vab/video", + "name": "scvideo", + "meta": { + "title": "视频播放器", + "type": "menu" + }, + "component": "vab/video" + }, + { + "path": "/vab/qrcode", + "name": "qrcode", + "meta": { + "title": "二维码", + "type": "menu" + }, + "component": "vab/qrcode" + } + ] + }, + { + "path": "/vab/form", + "name": "vabform", + "meta": { + "title": "Form 数据录入", + "icon": "el-icon-edit", + "type": "menu" + }, + "children": [ + { + "path": "/vab/tableselect", + "name": "tableselect", + "meta": { + "title": "表格选择器", + "type": "menu" + }, + "component": "vab/tableselect" + }, + { + "path": "/vab/formtable", + "name": "formtable", + "meta": { + "title": "表单表格", + "type": "menu" + }, + "component": "vab/formtable" + }, + { + "path": "/vab/selectFilter", + "name": "selectFilter", + "meta": { + "title": "分类筛选器", + "type": "menu" + }, + "component": "vab/selectFilter" + }, + { + "path": "/vab/filterbar", + "name": "filterBar", + "meta": { + "title": "过滤器v2", + "type": "menu" + }, + "component": "vab/filterBar" + }, + { + "path": "/vab/upload", + "name": "upload", + "meta": { + "title": "上传", + "type": "menu" + }, + "component": "vab/upload" + }, + { + "path": "/vab/select", + "name": "scselect", + "meta": { + "title": "异步选择器", + "type": "menu" + }, + "component": "vab/select" + }, + { + "path": "/vab/iconselect", + "name": "iconSelect", + "meta": { + "title": "图标选择器", + "type": "menu" + }, + "component": "vab/iconselect" + }, + { + "path": "/vab/cron", + "name": "cron", + "meta": { + "title": "Cron规则生成器", + "type": "menu" + }, + "component": "vab/cron" + }, + { + "path": "/vab/editor", + "name": "editor", + "meta": { + "title": "富文本编辑器", + "type": "menu" + }, + "component": "vab/editor" + }, + { + "path": "/vab/codeeditor", + "name": "codeeditor", + "meta": { + "title": "代码编辑器", + "type": "menu" + }, + "component": "vab/codeeditor" + } + ] + }, + { + "path": "/vab/feedback", + "name": "vabfeedback", + "meta": { + "title": "Feedback 反馈", + "icon": "el-icon-mouse", + "type": "menu" + }, + "children": [ + { + "path": "/vab/drag", + "name": "drag", + "meta": { + "title": "拖拽排序", + "type": "menu" + }, + "component": "vab/drag" + }, + { + "path": "/vab/contextmenu", + "name": "contextmenu", + "meta": { + "title": "右键菜单", + "type": "menu" + }, + "component": "vab/contextmenu" + }, + { + "path": "/vab/cropper", + "name": "cropper", + "meta": { + "title": "图像剪裁", + "type": "menu" + }, + "component": "vab/cropper" + }, + { + "path": "/vab/fileselect", + "name": "fileselect", + "meta": { + "title": "资源库选择器(弃用)", + "type": "menu" + }, + "component": "vab/fileselect" + }, + { + "path": "/vab/dialog", + "name": "dialogExtend", + "meta": { + "title": "弹窗扩展", + "type": "menu" + }, + "component": "vab/dialog" + } + ] + }, + { + "path": "/vab/others", + "name": "vabothers", + "meta": { + "title": "Others 其他", + "icon": "el-icon-more-filled", + "type": "menu" + }, + "children": [ + { + "path": "/vab/print", + "name": "print", + "meta": { + "title": "打印", + "type": "menu" + }, + "component": "vab/print" + }, + { + "path": "/vab/watermark", + "name": "watermark", + "meta": { + "title": "水印", + "type": "menu" + }, + "component": "vab/watermark" + }, + { + "path": "/vab/importexport", + "name": "importexport", + "meta": { + "title": "文件导出导入", + "type": "menu" + }, + "component": "vab/importexport" + } + ] + }, + { + "path": "/vab/list", + "name": "list", + "meta": { + "title": "Table 数据列表", + "icon": "el-icon-fold", + "type": "menu" + }, + "children": [ + { + "path": "/vab/table/base", + "name": "tableBase", + "meta": { + "title": "基础数据列表", + "type": "menu" + }, + "component": "vab/table/base" + }, + { + "path": "/vab/table/thead", + "name": "tableThead", + "meta": { + "title": "多级表头", + "type": "menu" + }, + "component": "vab/table/thead" + }, + { + "path": "/vab/table/column", + "name": "tableCustomColumn", + "meta": { + "title": "动态列", + "type": "menu" + }, + "component": "vab/table/column" + }, + { + "path": "/vab/table/remote", + "name": "tableRemote", + "meta": { + "title": "远程排序过滤", + "type": "menu" + }, + "component": "vab/table/remote" + } + ] + }, + { + "path": "/vab/workflow", + "name": "workflow", + "meta": { + "title": "工作流设计器", + "icon": "el-icon-share", + "type": "menu" + }, + "component": "vab/workflow" + }, + { + "path": "/vab/formrender", + "name": "formRender", + "meta": { + "title": "动态表单(Beta)", + "icon": "el-icon-message-box", + "type": "menu" + }, + "component": "vab/form" + } + ] + }, + { + "name": "template", + "path": "/template", + "meta": { + "title": "模板", + "icon": "el-icon-files", + "type": "menu" + }, + "children": [ + { + "path": "/template/layout", + "name": "layoutTemplate", + "meta": { + "title": "布局", + "icon": "el-icon-grid", + "type": "menu" + }, + "children": [ + { + "path": "/template/layout/blank", + "name": "blank", + "meta": { + "title": "空白模板", + "type": "menu" + }, + "component": "template/layout/blank" + }, + { + "path": "/template/layout/layoutTCB", + "name": "layoutTCB", + "meta": { + "title": "上中下布局", + "type": "menu" + }, + "component": "template/layout/layoutTCB" + }, + { + "path": "/template/layout/layoutLCR", + "name": "layoutLCR", + "meta": { + "title": "左中右布局", + "type": "menu" + }, + "component": "template/layout/layoutLCR" + } + ] + }, + { + "path": "/template/list", + "name": "list", + "meta": { + "title": "列表", + "icon": "el-icon-document", + "type": "menu" + }, + "children": [ + { + "path": "/template/list/crud", + "name": "listCrud", + "meta": { + "title": "CRUD", + "type": "menu" + }, + "component": "template/list/crud", + "children": [ + { + "path": "/template/list/crud/detail/:id?", + "name": "listCrud-detail", + "meta": { + "title": "新增/编辑", + "hidden": true, + "active": "/template/list/crud", + "type": "menu" + }, + "component": "template/list/crud/detail" + } + ] + }, + { + "path": "/template/list/tree", + "name": "listTree", + "meta": { + "title": "左树右表", + "type": "menu" + }, + "component": "template/list/tree" + }, + { + "path": "/template/list/tab", + "name": "listTab", + "meta": { + "title": "分类表格", + "type": "menu" + }, + "component": "template/list/tab" + }, + { + "path": "/template/list/son", + "name": "listSon", + "meta": { + "title": "子母表", + "type": "menu" + }, + "component": "template/list/son" + }, + { + "path": "/template/list/widthlist", + "name": "widthlist", + "meta": { + "title": "定宽列表", + "type": "menu" + }, + "component": "template/list/width" + } + ] + }, + { + "path": "/template/other", + "name": "other", + "meta": { + "title": "其他", + "icon": "el-icon-folder", + "type": "menu" + }, + "children": [ + { + "path": "/template/other/stepform", + "name": "stepform", + "meta": { + "title": "分步表单", + "type": "menu" + }, + "component": "template/other/stepform" + } + ] + } + ] + }, + { + "name": "other", + "path": "/other", + "meta": { + "title": "其他", + "icon": "el-icon-more-filled", + "type": "menu" + }, + "children": [ + { + "path": "/other/directive", + "name": "directive", + "meta": { + "title": "指令", + "icon": "el-icon-price-tag", + "type": "menu" + }, + "component": "other/directive" + }, + { + "path": "/other/viewTags", + "name": "viewTags", + "meta": { + "title": "标签操作", + "icon": "el-icon-files", + "type": "menu" + }, + "component": "other/viewTags", + "children": [ + { + "path": "/other/fullpage", + "name": "fullpage", + "meta": { + "title": "整页路由", + "icon": "el-icon-monitor", + "fullpage": true, + "hidden": true, + "type": "menu" + }, + "component": "other/fullpage" + } + ] + }, + { + "path": "/other/verificate", + "name": "verificate", + "meta": { + "title": "表单验证", + "icon": "el-icon-open", + "type": "menu" + }, + "component": "other/verificate" + }, + { + "path": "/other/loadJS", + "name": "loadJS", + "meta": { + "title": "异步加载JS", + "icon": "el-icon-location-information", + "type": "menu" + }, + "component": "other/loadJS" + }, + { + "path": "/link", + "name": "link", + "meta": { + "title": "外部链接", + "icon": "el-icon-link", + "type": "menu" + }, + "children": [ + { + "path": "https://baidu.com", + "name": "百度", + "meta": { + "title": "百度", + "type": "link" + } + }, + { + "path": "https://www.google.cn", + "name": "谷歌", + "meta": { + "title": "谷歌", + "type": "link" + } + } + ] + }, + { + "path": "/iframe", + "name": "Iframe", + "meta": { + "title": "Iframe", + "icon": "el-icon-position", + "type": "menu" + }, + "children": [ + { + "path": "https://v3.cn.vuejs.org", + "name": "vue3", + "meta": { + "title": "VUE 3", + "type": "iframe" + } + }, + { + "path": "https://element-plus.gitee.io", + "name": "elementplus", + "meta": { + "title": "Element Plus", + "type": "iframe" + } + }, + { + "path": "https://lolicode.gitee.io/scui-doc", + "name": "scuidoc", + "meta": { + "title": "SCUI文档", + "type": "iframe" + } + } + ] + } + ] + }, + { + "name": "test", + "path": "/test", + "meta": { + "title": "实验室", + "icon": "el-icon-mouse", + "type": "menu" + }, + "children": [ + { + "path": "/test/autocode", + "name": "autocode", + "meta": { + "title": "代码生成器", + "icon": "sc-icon-code", + "type": "menu" + }, + "component": "test/autocode/index", + "children": [ + { + "path": "/test/autocode/table", + "name": "autocode-table", + "meta": { + "title": "CRUD代码生成", + "hidden": true, + "active": "/test/autocode", + "type": "menu" + }, + "component": "test/autocode/table" + } + ] + }, + { + "path": "/test/codebug", + "name": "codebug", + "meta": { + "title": "异常处理", + "icon": "sc-icon-bug-line", + "type": "menu" + }, + "component": "test/codebug" + } + ] + }, + { + "name": "setting", + "path": "/setting", + "meta": { + "title": "配置", + "icon": "el-icon-setting", + "type": "menu" + }, + "children": [ + { + "path": "/setting/system", + "name": "system", + "meta": { + "title": "系统设置", + "icon": "el-icon-tools", + "type": "menu" + }, + "component": "setting/system" + }, + { + "path": "/setting/user", + "name": "user", + "meta": { + "title": "用户管理", + "icon": "el-icon-user-filled", + "type": "menu" + }, + "component": "setting/user" + }, + { + "path": "/setting/role", + "name": "role", + "meta": { + "title": "角色管理", + "icon": "el-icon-notebook", + "type": "menu" + }, + "component": "setting/role" + }, + { + "path": "/setting/dept", + "name": "dept", + "meta": { + "title": "部门管理", + "icon": "sc-icon-organization", + "type": "menu" + }, + "component": "setting/dept" + }, + { + "path": "/setting/dic", + "name": "dic", + "meta": { + "title": "字典管理", + "icon": "el-icon-document", + "type": "menu" + }, + "component": "setting/dic" + }, + { + "path": "/setting/table", + "name": "tableSetting", + "meta": { + "title": "表格列管理", + "icon": "el-icon-scale-to-original", + "type": "menu" + }, + "component": "setting/table" + }, + { + "path": "/setting/menu", + "name": "settingMenu", + "meta": { + "title": "菜单管理", + "icon": "el-icon-fold", + "type": "menu" + }, + "component": "setting/menu" + }, + { + "path": "/setting/task", + "name": "task", + "meta": { + "title": "计划任务", + "icon": "el-icon-alarm-clock", + "type": "menu" + }, + "component": "setting/task" + }, + { + "path": "/setting/client", + "name": "client", + "meta": { + "title": "应用管理", + "icon": "el-icon-help-filled", + "type": "menu" + }, + "component": "setting/client" + }, + { + "path": "/setting/log", + "name": "log", + "meta": { + "title": "系统日志", + "icon": "el-icon-warning", + "type": "menu" + }, + "component": "setting/log" + } + ] + }, + { + "path": "/other/about", + "name": "about", + "meta": { + "title": "关于", + "icon": "el-icon-info-filled", + "type": "menu" + }, + "component": "other/about" + } +] \ No newline at end of file diff --git a/process/Monitor.php b/process/Monitor.php new file mode 100644 index 0000000..92b3716 --- /dev/null +++ b/process/Monitor.php @@ -0,0 +1,243 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace process; + +use FilesystemIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use SplFileInfo; +use Workerman\Timer; +use Workerman\Worker; + +/** + * Class FileMonitor + * @package process + */ +class Monitor +{ + /** + * @var array + */ + protected $paths = []; + + /** + * @var array + */ + protected $extensions = []; + + /** + * @var string + */ + public static $lockFile = __DIR__ . '/../runtime/monitor.lock'; + + /** + * Pause monitor + * @return void + */ + public static function pause() + { + file_put_contents(static::$lockFile, time()); + } + + /** + * Resume monitor + * @return void + */ + public static function resume(): void + { + clearstatcache(); + if (is_file(static::$lockFile)) { + unlink(static::$lockFile); + } + } + + /** + * Whether monitor is paused + * @return bool + */ + public static function isPaused(): bool + { + clearstatcache(); + return file_exists(static::$lockFile); + } + + /** + * FileMonitor constructor. + * @param $monitorDir + * @param $monitorExtensions + * @param array $options + */ + public function __construct($monitorDir, $monitorExtensions, array $options = []) + { + static::resume(); + $this->paths = (array)$monitorDir; + $this->extensions = $monitorExtensions; + if (!Worker::getAllWorkers()) { + return; + } + $disableFunctions = explode(',', ini_get('disable_functions')); + if (in_array('exec', $disableFunctions, true)) { + echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n"; + } else { + if ($options['enable_file_monitor'] ?? true) { + Timer::add(1, function () { + $this->checkAllFilesChange(); + }); + } + } + + $memoryLimit = $this->getMemoryLimit($options['memory_limit'] ?? null); + if ($memoryLimit && ($options['enable_memory_monitor'] ?? true)) { + Timer::add(60, [$this, 'checkMemory'], [$memoryLimit]); + } + } + + /** + * @param $monitorDir + * @return bool + */ + public function checkFilesChange($monitorDir): bool + { + static $lastMtime, $tooManyFilesCheck; + if (!$lastMtime) { + $lastMtime = time(); + } + clearstatcache(); + if (!is_dir($monitorDir)) { + if (!is_file($monitorDir)) { + return false; + } + $iterator = [new SplFileInfo($monitorDir)]; + } else { + // recursive traversal directory + $dirIterator = new RecursiveDirectoryIterator($monitorDir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS); + $iterator = new RecursiveIteratorIterator($dirIterator); + } + $count = 0; + foreach ($iterator as $file) { + $count ++; + /** var SplFileInfo $file */ + if (is_dir($file->getRealPath())) { + continue; + } + // check mtime + if (in_array($file->getExtension(), $this->extensions, true) && $lastMtime < $file->getMTime()) { + $var = 0; + exec('"'.PHP_BINARY . '" -l ' . $file, $out, $var); + $lastMtime = $file->getMTime(); + if ($var) { + continue; + } + echo $file . " update and reload\n"; + // send SIGUSR1 signal to master process for reload + if (DIRECTORY_SEPARATOR === '/') { + posix_kill(posix_getppid(), SIGUSR1); + } else { + return true; + } + break; + } + } + if (!$tooManyFilesCheck && $count > 1000) { + echo "Monitor: There are too many files ($count files) in $monitorDir which makes file monitoring very slow\n"; + $tooManyFilesCheck = 1; + } + return false; + } + + /** + * @return bool + */ + public function checkAllFilesChange(): bool + { + if (static::isPaused()) { + return false; + } + foreach ($this->paths as $path) { + if ($this->checkFilesChange($path)) { + return true; + } + } + return false; + } + + /** + * @param $memoryLimit + * @return void + */ + public function checkMemory($memoryLimit) + { + if (static::isPaused() || $memoryLimit <= 0) { + return; + } + $ppid = posix_getppid(); + $childrenFile = "/proc/$ppid/task/$ppid/children"; + if (!is_file($childrenFile) || !($children = file_get_contents($childrenFile))) { + return; + } + foreach (explode(' ', $children) as $pid) { + $pid = (int)$pid; + $statusFile = "/proc/$pid/status"; + if (!is_file($statusFile) || !($status = file_get_contents($statusFile))) { + continue; + } + $mem = 0; + if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) { + $mem = $match[1]; + } + $mem = (int)($mem / 1024); + if ($mem >= $memoryLimit) { + posix_kill($pid, SIGINT); + } + } + } + + /** + * Get memory limit + * @return float + */ + protected function getMemoryLimit($memoryLimit) + { + if ($memoryLimit === 0) { + return 0; + } + $usePhpIni = false; + if (!$memoryLimit) { + $memoryLimit = ini_get('memory_limit'); + $usePhpIni = true; + } + + if ($memoryLimit == -1) { + return 0; + } + $unit = strtolower($memoryLimit[strlen($memoryLimit) - 1]); + if ($unit === 'g') { + $memoryLimit = 1024 * (int)$memoryLimit; + } else if ($unit === 'm') { + $memoryLimit = (int)$memoryLimit; + } else if ($unit === 'k') { + $memoryLimit = ((int)$memoryLimit / 1024); + } else { + $memoryLimit = ((int)$memoryLimit / (1024 * 1024)); + } + if ($memoryLimit < 30) { + $memoryLimit = 30; + } + if ($usePhpIni) { + $memoryLimit = (int)(0.8 * $memoryLimit); + } + return $memoryLimit; + } +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..2bde119 --- /dev/null +++ b/public/404.html @@ -0,0 +1,12 @@ + + + 404 Not Found - webman + + +
+

404 Not Found

+
+
+
webman
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..b9f722e Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/upload/1db32242bd37b55e47044ee247efbc6b.png b/public/upload/1db32242bd37b55e47044ee247efbc6b.png new file mode 100644 index 0000000..dff7722 Binary files /dev/null and b/public/upload/1db32242bd37b55e47044ee247efbc6b.png differ diff --git a/public/upload/5a9c5229b86b7356a61e028ea84de595.png b/public/upload/5a9c5229b86b7356a61e028ea84de595.png new file mode 100644 index 0000000..d35c1aa Binary files /dev/null and b/public/upload/5a9c5229b86b7356a61e028ea84de595.png differ diff --git a/public/upload/9ea0d97468af1cb2b93d1533554ccd75.png b/public/upload/9ea0d97468af1cb2b93d1533554ccd75.png new file mode 100644 index 0000000..dff7722 Binary files /dev/null and b/public/upload/9ea0d97468af1cb2b93d1533554ccd75.png differ diff --git a/public/upload/cbee89969a0dd40a1a5215b69c8966a4.png b/public/upload/cbee89969a0dd40a1a5215b69c8966a4.png new file mode 100644 index 0000000..d35c1aa Binary files /dev/null and b/public/upload/cbee89969a0dd40a1a5215b69c8966a4.png differ diff --git a/public/upload/e1ad5490fd1834263593fb148bbad54f.png b/public/upload/e1ad5490fd1834263593fb148bbad54f.png new file mode 100644 index 0000000..d35c1aa Binary files /dev/null and b/public/upload/e1ad5490fd1834263593fb148bbad54f.png differ diff --git a/public/upload/f89bb898e2777183308b98a25fd25413.png b/public/upload/f89bb898e2777183308b98a25fd25413.png new file mode 100644 index 0000000..d35c1aa Binary files /dev/null and b/public/upload/f89bb898e2777183308b98a25fd25413.png differ diff --git a/start.php b/start.php new file mode 100644 index 0000000..489e447 --- /dev/null +++ b/start.php @@ -0,0 +1,4 @@ +#!/usr/bin/env php + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace support; + +/** + * Class Request + * @package support + */ +class Request extends \Webman\Http\Request +{ + +} \ No newline at end of file diff --git a/support/Response.php b/support/Response.php new file mode 100644 index 0000000..9bc4e1e --- /dev/null +++ b/support/Response.php @@ -0,0 +1,24 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace support; + +/** + * Class Response + * @package support + */ +class Response extends \Webman\Http\Response +{ + +} \ No newline at end of file diff --git a/support/bootstrap.php b/support/bootstrap.php new file mode 100644 index 0000000..d9471e6 --- /dev/null +++ b/support/bootstrap.php @@ -0,0 +1,133 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use Dotenv\Dotenv; +use support\Log; +use Webman\Bootstrap; +use Webman\Config; +use Webman\Middleware; +use Webman\Route; +use Webman\Util; + +$worker = $worker ?? null; + +set_error_handler(function ($level, $message, $file = '', $line = 0) { + if (error_reporting() & $level) { + throw new ErrorException($message, 0, $level, $file, $line); + } +}); + +if ($worker) { + register_shutdown_function(function ($startTime) { + if (time() - $startTime <= 0.1) { + sleep(1); + } + }, time()); +} + +if (class_exists('Dotenv\Dotenv') && file_exists(base_path(false) . '/.env')) { + if (method_exists('Dotenv\Dotenv', 'createUnsafeMutable')) { + Dotenv::createUnsafeMutable(base_path(false))->load(); + } else { + Dotenv::createMutable(base_path(false))->load(); + } +} + +Config::clear(); +support\App::loadAllConfig(['route']); +if ($timezone = config('app.default_timezone')) { + date_default_timezone_set($timezone); +} + +foreach (config('autoload.files', []) as $file) { + include_once $file; +} +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['autoload']['files'] ?? [] as $file) { + include_once $file; + } + } + foreach ($projects['autoload']['files'] ?? [] as $file) { + include_once $file; + } +} + +Middleware::load(config('middleware', [])); +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project) || $name === 'static') { + continue; + } + Middleware::load($project['middleware'] ?? []); + } + Middleware::load($projects['middleware'] ?? [], $firm); + if ($staticMiddlewares = config("plugin.$firm.static.middleware")) { + Middleware::load(['__static__' => $staticMiddlewares], $firm); + } +} +Middleware::load(['__static__' => config('static.middleware', [])]); + +foreach (config('bootstrap', []) as $className) { + if (!class_exists($className)) { + $log = "Warning: Class $className setting in config/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); +} + +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['bootstrap'] ?? [] as $className) { + if (!class_exists($className)) { + $log = "Warning: Class $className setting in config/plugin/$firm/$name/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); + } + } + foreach ($projects['bootstrap'] ?? [] as $className) { + /** @var string $className */ + if (!class_exists($className)) { + $log = "Warning: Class $className setting in plugin/$firm/config/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); + } +} + +$directory = base_path() . '/plugin'; +$paths = [config_path()]; +foreach (Util::scanDir($directory) as $path) { + if (is_dir($path = "$path/config")) { + $paths[] = $path; + } +} +Route::load($paths); + diff --git a/support/helpers.php b/support/helpers.php new file mode 100644 index 0000000..8de22c0 --- /dev/null +++ b/support/helpers.php @@ -0,0 +1,528 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\Container; +use support\Request; +use support\Response; +use support\Translation; +use support\view\Blade; +use support\view\Raw; +use support\view\ThinkPHP; +use support\view\Twig; +use Twig\Error\LoaderError; +use Twig\Error\RuntimeError; +use Twig\Error\SyntaxError; +use Webman\App; +use Webman\Config; +use Webman\Route; +use Workerman\Protocols\Http\Session; +use Workerman\Worker; + +// Project base path +define('BASE_PATH', dirname(__DIR__)); + +/** + * return the program execute directory + * @param string $path + * @return string + */ +function run_path(string $path = ''): string +{ + static $runPath = ''; + if (!$runPath) { + $runPath = is_phar() ? dirname(Phar::running(false)) : BASE_PATH; + } + return path_combine($runPath, $path); +} + +/** + * if the param $path equal false,will return this program current execute directory + * @param string|false $path + * @return string + */ +function base_path($path = ''): string +{ + if (false === $path) { + return run_path(); + } + return path_combine(BASE_PATH, $path); +} + +/** + * App path + * @param string $path + * @return string + */ +function app_path(string $path = ''): string +{ + return path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'app', $path); +} + +/** + * Public path + * @param string $path + * @return string + */ +function public_path(string $path = ''): string +{ + static $publicPath = ''; + if (!$publicPath) { + $publicPath = \config('app.public_path') ?: run_path('public'); + } + return path_combine($publicPath, $path); +} + +/** + * Config path + * @param string $path + * @return string + */ +function config_path(string $path = ''): string +{ + return path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'config', $path); +} + +/** + * Runtime path + * @param string $path + * @return string + */ +function runtime_path(string $path = ''): string +{ + static $runtimePath = ''; + if (!$runtimePath) { + $runtimePath = \config('app.runtime_path') ?: run_path('runtime'); + } + return path_combine($runtimePath, $path); +} + +/** + * Generate paths based on given information + * @param string $front + * @param string $back + * @return string + */ +function path_combine(string $front, string $back): string +{ + return $front . ($back ? (DIRECTORY_SEPARATOR . ltrim($back, DIRECTORY_SEPARATOR)) : $back); +} + +/** + * Response + * @param int $status + * @param array $headers + * @param string $body + * @return Response + */ +function response(string $body = '', int $status = 200, array $headers = []): Response +{ + return new Response($status, $headers, $body); +} + +/** + * Json response + * @param $data + * @param int $options + * @return Response + */ +function json($data, int $options = JSON_UNESCAPED_UNICODE): Response +{ + return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options)); +} + +/** + * Xml response + * @param $xml + * @return Response + */ +function xml($xml): Response +{ + if ($xml instanceof SimpleXMLElement) { + $xml = $xml->asXML(); + } + return new Response(200, ['Content-Type' => 'text/xml'], $xml); +} + +/** + * Jsonp response + * @param $data + * @param string $callbackName + * @return Response + */ +function jsonp($data, string $callbackName = 'callback'): Response +{ + if (!is_scalar($data) && null !== $data) { + $data = json_encode($data); + } + return new Response(200, [], "$callbackName($data)"); +} + +/** + * Redirect response + * @param string $location + * @param int $status + * @param array $headers + * @return Response + */ +function redirect(string $location, int $status = 302, array $headers = []): Response +{ + $response = new Response($status, ['Location' => $location]); + if (!empty($headers)) { + $response->withHeaders($headers); + } + return $response; +} + +/** + * View response + * @param string $template + * @param array $vars + * @param string|null $app + * @param string|null $plugin + * @return Response + */ +function view(string $template, array $vars = [], string $app = null, string $plugin = null): Response +{ + $request = \request(); + $plugin = $plugin === null ? ($request->plugin ?? '') : $plugin; + $handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler'); + return new Response(200, [], $handler::render($template, $vars, $app, $plugin)); +} + +/** + * Raw view response + * @param string $template + * @param array $vars + * @param string|null $app + * @return Response + * @throws Throwable + */ +function raw_view(string $template, array $vars = [], string $app = null): Response +{ + return new Response(200, [], Raw::render($template, $vars, $app)); +} + +/** + * Blade view response + * @param string $template + * @param array $vars + * @param string|null $app + * @return Response + */ +function blade_view(string $template, array $vars = [], string $app = null): Response +{ + return new Response(200, [], Blade::render($template, $vars, $app)); +} + +/** + * Think view response + * @param string $template + * @param array $vars + * @param string|null $app + * @return Response + */ +function think_view(string $template, array $vars = [], string $app = null): Response +{ + return new Response(200, [], ThinkPHP::render($template, $vars, $app)); +} + +/** + * Twig view response + * @param string $template + * @param array $vars + * @param string|null $app + * @return Response + * @throws LoaderError + * @throws RuntimeError + * @throws SyntaxError + */ +function twig_view(string $template, array $vars = [], string $app = null): Response +{ + return new Response(200, [], Twig::render($template, $vars, $app)); +} + +/** + * Get request + * @return \Webman\Http\Request|Request|null + */ +function request() +{ + return App::request(); +} + +/** + * Get config + * @param string|null $key + * @param $default + * @return array|mixed|null + */ +function config(string $key = null, $default = null) +{ + return Config::get($key, $default); +} + +/** + * Create url + * @param string $name + * @param ...$parameters + * @return string + */ +function route(string $name, ...$parameters): string +{ + $route = Route::getByName($name); + if (!$route) { + return ''; + } + + if (!$parameters) { + return $route->url(); + } + + if (is_array(current($parameters))) { + $parameters = current($parameters); + } + + return $route->url($parameters); +} + +/** + * Session + * @param mixed $key + * @param mixed $default + * @return mixed|bool|Session + */ +function session($key = null, $default = null) +{ + $session = \request()->session(); + if (null === $key) { + return $session; + } + if (is_array($key)) { + $session->put($key); + return null; + } + if (strpos($key, '.')) { + $keyArray = explode('.', $key); + $value = $session->all(); + foreach ($keyArray as $index) { + if (!isset($value[$index])) { + return $default; + } + $value = $value[$index]; + } + return $value; + } + return $session->get($key, $default); +} + +/** + * Translation + * @param string $id + * @param array $parameters + * @param string|null $domain + * @param string|null $locale + * @return string + */ +function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string +{ + $res = Translation::trans($id, $parameters, $domain, $locale); + return $res === '' ? $id : $res; +} + +/** + * Locale + * @param string|null $locale + * @return string + */ +function locale(string $locale = null): string +{ + if (!$locale) { + return Translation::getLocale(); + } + Translation::setLocale($locale); + return $locale; +} + +/** + * 404 not found + * @return Response + */ +function not_found(): Response +{ + return new Response(404, [], file_get_contents(public_path() . '/404.html')); +} + +/** + * Copy dir + * @param string $source + * @param string $dest + * @param bool $overwrite + * @return void + */ +function copy_dir(string $source, string $dest, bool $overwrite = false) +{ + if (is_dir($source)) { + if (!is_dir($dest)) { + mkdir($dest); + } + $files = scandir($source); + foreach ($files as $file) { + if ($file !== "." && $file !== "..") { + copy_dir("$source/$file", "$dest/$file", $overwrite); + } + } + } else if (file_exists($source) && ($overwrite || !file_exists($dest))) { + copy($source, $dest); + } +} + +/** + * Remove dir + * @param string $dir + * @return bool + */ +function remove_dir(string $dir): bool +{ + if (is_link($dir) || is_file($dir)) { + return unlink($dir); + } + $files = array_diff(scandir($dir), array('.', '..')); + foreach ($files as $file) { + (is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file"); + } + return rmdir($dir); +} + +/** + * Bind worker + * @param $worker + * @param $class + */ +function worker_bind($worker, $class) +{ + $callbackMap = [ + 'onConnect', + 'onMessage', + 'onClose', + 'onError', + 'onBufferFull', + 'onBufferDrain', + 'onWorkerStop', + 'onWebSocketConnect', + 'onWorkerReload' + ]; + foreach ($callbackMap as $name) { + if (method_exists($class, $name)) { + $worker->$name = [$class, $name]; + } + } + if (method_exists($class, 'onWorkerStart')) { + call_user_func([$class, 'onWorkerStart'], $worker); + } +} + +/** + * Start worker + * @param $processName + * @param $config + * @return void + */ +function worker_start($processName, $config) +{ + $worker = new Worker($config['listen'] ?? null, $config['context'] ?? []); + $propertyMap = [ + 'count', + 'user', + 'group', + 'reloadable', + 'reusePort', + 'transport', + 'protocol', + ]; + $worker->name = $processName; + foreach ($propertyMap as $property) { + if (isset($config[$property])) { + $worker->$property = $config[$property]; + } + } + + $worker->onWorkerStart = function ($worker) use ($config) { + require_once base_path('/support/bootstrap.php'); + if (isset($config['handler'])) { + if (!class_exists($config['handler'])) { + echo "process error: class {$config['handler']} not exists\r\n"; + return; + } + + $instance = Container::make($config['handler'], $config['constructor'] ?? []); + worker_bind($worker, $instance); + } + }; +} + +/** + * Get realpath + * @param string $filePath + * @return string + */ +function get_realpath(string $filePath): string +{ + if (strpos($filePath, 'phar://') === 0) { + return $filePath; + } else { + return realpath($filePath); + } +} + +/** + * Is phar + * @return bool + */ +function is_phar(): bool +{ + return class_exists(Phar::class, false) && Phar::running(); +} + +/** + * Get cpu count + * @return int + */ +function cpu_count(): int +{ + // Windows does not support the number of processes setting. + if (DIRECTORY_SEPARATOR === '\\') { + return 1; + } + $count = 4; + if (is_callable('shell_exec')) { + if (strtolower(PHP_OS) === 'darwin') { + $count = (int)shell_exec('sysctl -n machdep.cpu.core_count'); + } else { + $count = (int)shell_exec('nproc'); + } + } + return $count > 0 ? $count : 4; +} + +/** + * Get request parameters, if no parameter name is passed, an array of all values is returned, default values is supported + * @param string|null $param param's name + * @param mixed|null $default default value + * @return mixed|null + */ +function input(string $param = null, $default = null) +{ + return is_null($param) ? request()->all() : request()->input($param, $default); +} diff --git a/test.php b/test.php new file mode 100644 index 0000000..84ee22c --- /dev/null +++ b/test.php @@ -0,0 +1,6 @@ +setName('webman cli'); +$cli->installInternalCommands(); +if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) { + $cli->installCommands($command_path); +} + +foreach (config('plugin', []) as $firm => $projects) { + if (isset($projects['app'])) { + if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) { + $command_path = base_path() . "/plugin/$firm/$command_str"; + $cli->installCommands($command_path, "plugin\\$firm\\$command_str"); + } + } + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['command'] ?? [] as $class_name) { + $reflection = new \ReflectionClass($class_name); + if ($reflection->isAbstract()) { + continue; + } + $properties = $reflection->getStaticProperties(); + $name = $properties['defaultName']; + if (!$name) { + throw new RuntimeException("Command {$class_name} has no defaultName"); + } + $description = $properties['defaultDescription'] ?? ''; + $command = Container::get($class_name); + $command->setName($name)->setDescription($description); + $cli->add($command); + } + } +} + +$cli->run(); diff --git a/windows.bat b/windows.bat new file mode 100644 index 0000000..f07ce53 --- /dev/null +++ b/windows.bat @@ -0,0 +1,3 @@ +CHCP 65001 +php windows.php +pause \ No newline at end of file diff --git a/windows.php b/windows.php new file mode 100644 index 0000000..21fa888 --- /dev/null +++ b/windows.php @@ -0,0 +1,118 @@ +load(); + } else { + Dotenv::createMutable(base_path())->load(); + } +} + +App::loadAllConfig(['route']); + +$errorReporting = config('app.error_reporting'); +if (isset($errorReporting)) { + error_reporting($errorReporting); +} + +$runtimeProcessPath = runtime_path() . DIRECTORY_SEPARATOR . '/windows'; +if (!is_dir($runtimeProcessPath)) { + mkdir($runtimeProcessPath); +} +$processFiles = [ + __DIR__ . DIRECTORY_SEPARATOR . 'start.php' +]; +foreach (config('process', []) as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, ''); +} + +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['process'] ?? [] as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, "$firm.$name"); + } + } + foreach ($projects['process'] ?? [] as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, $firm); + } +} + +function write_process_file($runtimeProcessPath, $processName, $firm): string +{ + $processParam = $firm ? "plugin.$firm.$processName" : $processName; + $configParam = $firm ? "config('plugin.$firm.process')['$processName']" : "config('process')['$processName']"; + $fileContent = << true]); + if (!$resource) { + exit("Can not execute $cmd\r\n"); + } + return $resource; +} + +$resource = popen_processes($processFiles); +echo "\r\n"; +while (1) { + sleep(1); + if (!empty($monitor) && $monitor->checkAllFilesChange()) { + $status = proc_get_status($resource); + $pid = $status['pid']; + shell_exec("taskkill /F /T /PID $pid"); + proc_close($resource); + $resource = popen_processes($processFiles); + } +}