From 5459299af14dabd6ac40b998524b841e2baaa95d Mon Sep 17 00:00:00 2001 From: zhaoxiang Date: Wed, 24 Apr 2019 15:35:50 +0800 Subject: [PATCH] =?UTF-8?q?modified=20=E8=BD=AC=E7=A7=BB3.0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=80=A7=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/admin/controller/App.php | 198 ++++++++++++ application/admin/controller/AppGroup.php | 137 ++++++++ application/admin/controller/Auth.php | 296 ++++++++++++++++++ application/admin/controller/Base.php | 57 ++++ application/admin/controller/Fields.php | 264 ++++++++++++++++ application/admin/controller/Index.php | 53 ++++ .../admin/controller/InterfaceGroup.php | 160 ++++++++++ .../admin/controller/InterfaceList.php | 194 ++++++++++++ application/admin/controller/Log.php | 72 +++++ application/admin/controller/Login.php | 101 ++++++ application/admin/controller/Menu.php | 108 +++++++ application/admin/controller/Miss.php | 15 + application/admin/controller/User.php | 269 ++++++++++++++++ application/api/controller/Base.php | 56 ++++ application/api/controller/BuildToken.php | 90 ++++++ application/api/controller/Index.php | 19 ++ application/api/controller/Miss.php | 22 ++ application/index/controller/Index.php | 15 - application/model/AdminApp.php | 8 + application/model/AdminAppGroup.php | 13 + application/model/AdminAuthGroup.php | 17 + application/model/AdminAuthGroupAccess.php | 13 + application/model/AdminAuthRule.php | 13 + application/model/AdminFields.php | 12 + application/model/AdminGroup.php | 13 + application/model/AdminList.php | 11 + application/model/AdminMenu.php | 8 + application/model/AdminUser.php | 12 + application/model/AdminUserAction.php | 13 + application/model/AdminUserData.php | 12 + application/model/Base.php | 15 + application/util/ApiLog.php | 109 +++++++ application/util/BuildName.php | 106 +++++++ application/util/DataType.php | 24 ++ application/util/MockConf.php | 21 ++ application/util/ReturnCode.php | 49 +++ application/util/StrRandom.php | 186 +++++++++++ application/util/Strs.php | 252 +++++++++++++++ application/util/Tools.php | 115 +++++++ application/wiki/controller/Base.php | 90 ++++++ application/wiki/controller/Index.php | 178 +++++++++++ application/wiki/view/index/calculation.html | 44 +++ application/wiki/view/index/detail.html | 199 ++++++++++++ application/wiki/view/index/error_code.html | 45 +++ application/wiki/view/index/index.html | 78 +++++ application/wiki/view/index/login.html | 96 ++++++ composer.json | 4 +- composer.lock | 147 ++++++++- config/app.php | 2 +- config/cache.php | 3 +- config/database.php | 4 +- 51 files changed, 4014 insertions(+), 24 deletions(-) create mode 100644 application/admin/controller/App.php create mode 100644 application/admin/controller/AppGroup.php create mode 100644 application/admin/controller/Auth.php create mode 100644 application/admin/controller/Base.php create mode 100644 application/admin/controller/Fields.php create mode 100644 application/admin/controller/Index.php create mode 100644 application/admin/controller/InterfaceGroup.php create mode 100644 application/admin/controller/InterfaceList.php create mode 100644 application/admin/controller/Log.php create mode 100644 application/admin/controller/Login.php create mode 100644 application/admin/controller/Menu.php create mode 100644 application/admin/controller/Miss.php create mode 100644 application/admin/controller/User.php create mode 100644 application/api/controller/Base.php create mode 100644 application/api/controller/BuildToken.php create mode 100644 application/api/controller/Index.php create mode 100644 application/api/controller/Miss.php delete mode 100644 application/index/controller/Index.php create mode 100644 application/model/AdminApp.php create mode 100644 application/model/AdminAppGroup.php create mode 100644 application/model/AdminAuthGroup.php create mode 100644 application/model/AdminAuthGroupAccess.php create mode 100644 application/model/AdminAuthRule.php create mode 100644 application/model/AdminFields.php create mode 100644 application/model/AdminGroup.php create mode 100644 application/model/AdminList.php create mode 100644 application/model/AdminMenu.php create mode 100644 application/model/AdminUser.php create mode 100644 application/model/AdminUserAction.php create mode 100644 application/model/AdminUserData.php create mode 100644 application/model/Base.php create mode 100644 application/util/ApiLog.php create mode 100644 application/util/BuildName.php create mode 100644 application/util/DataType.php create mode 100644 application/util/MockConf.php create mode 100644 application/util/ReturnCode.php create mode 100644 application/util/StrRandom.php create mode 100644 application/util/Strs.php create mode 100644 application/util/Tools.php create mode 100644 application/wiki/controller/Base.php create mode 100644 application/wiki/controller/Index.php create mode 100644 application/wiki/view/index/calculation.html create mode 100644 application/wiki/view/index/detail.html create mode 100644 application/wiki/view/index/error_code.html create mode 100644 application/wiki/view/index/index.html create mode 100644 application/wiki/view/index/login.html diff --git a/application/admin/controller/App.php b/application/admin/controller/App.php new file mode 100644 index 0000000..7afbefc --- /dev/null +++ b/application/admin/controller/App.php @@ -0,0 +1,198 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminApp; +use app\model\AdminList; +use app\model\AdminGroup; +use app\util\ReturnCode; +use app\util\Strs; +use app\util\Tools; + +class App extends Base { + /** + * 获取应用列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $keywords = $this->request->get('keywords', ''); + $type = $this->request->get('type', ''); + $status = $this->request->get('status', ''); + + $where = []; + if ($status === '1' || $status === '0') { + $where['app_status'] = $status; + } + if ($type) { + switch ($type) { + case 1: + $where['app_id'] = $keywords; + break; + case 2: + $where['app_name'] = ['like', "%{$keywords}%"]; + break; + } + } + $listObj = (new AdminApp())->where($where)->order('app_addTime DESC') + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 获取AppId,AppSecret,接口列表,应用接口权限细节 + * @author zhaoxiang + * @return array + * @throws \think\Exception + * @throws \think\exception\DbException + */ + public function getAppInfo() { + $apiArr = AdminList::all(); + foreach ($apiArr as $api) { + $res['apiList'][$api['groupHash']][] = $api; + } + $groupArr = AdminGroup::all(); + $groupArr = Tools::buildArrFromObj($groupArr); + $res['groupInfo'] = array_column($groupArr, 'name', 'hash'); + $id = $this->request->get('id', 0); + if ($id) { + $appInfo = AdminApp::get($id)->toArray(); + $res['app_detail'] = json_decode($appInfo['app_api_show'], true); + } else { + $res['app_id'] = mt_rand(1, 9) . Strs::randString(7, 1); + $res['app_secret'] = Strs::randString(32); + } + + return $this->buildSuccess($res); + } + + /** + * 刷新APPSecret + * @author zhaoxiang + * @return array + */ + public function refreshAppSecret() { + $id = $this->request->get('id', 0); + $data['app_secret'] = Strs::randString(32); + if ($id) { + $res = AdminApp::update($data, ['id' => $id]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } + } + + return $this->buildSuccess($data); + } + + /** + * 新增应用 + * @return array + * @author zhaoxiang + */ + public function add() { + $postData = $this->request->post(); + $data = [ + 'app_id' => $postData['app_id'], + 'app_secret' => $postData['app_secret'], + 'app_name' => $postData['app_name'], + 'app_info' => $postData['app_info'], + 'app_group' => $postData['app_group'], + 'app_addTime' => time(), + 'app_api' => '', + 'app_api_show' => '', + ]; + if (isset($postData['app_api']) && $postData['app_api']) { + $appApi = []; + $data['app_api_show'] = json_encode($postData['app_api']); + foreach ($postData['app_api'] as $value) { + $appApi = array_merge($appApi, $value); + } + $data['app_api'] = implode(',', $appApi); + } + $res = AdminApp::create($data); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 应用状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminApp::update([ + 'app_status' => $status + ], [ + 'id' => $id + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 编辑应用 + * @return array + * @author zhaoxiang + */ + public function edit() { + $postData = $this->request->post(); + $data = [ + 'app_name' => $postData['app_name'], + 'app_info' => $postData['app_info'], + 'app_group' => $postData['app_group'], + 'app_api' => '', + 'app_api_show' => '', + ]; + if (isset($postData['app_api']) && $postData['app_api']) { + $appApi = []; + $data['app_api_show'] = json_encode($postData['app_api']); + foreach ($postData['app_api'] as $value) { + $appApi = array_merge($appApi, $value); + } + $data['app_api'] = implode(',', $appApi); + } + $res = AdminApp::update($data, ['id' => $postData['id']]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 删除应用 + * @return array + * @author zhaoxiang + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + AdminApp::destroy($id); + + return $this->buildSuccess([]); + } +} diff --git a/application/admin/controller/AppGroup.php b/application/admin/controller/AppGroup.php new file mode 100644 index 0000000..3ee1d6f --- /dev/null +++ b/application/admin/controller/AppGroup.php @@ -0,0 +1,137 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminApp; +use app\model\AdminAppGroup; +use app\util\ReturnCode; +use app\util\Tools; + +class AppGroup extends Base { + /** + * 获取应用组列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $keywords = $this->request->get('keywords', ''); + $type = $this->request->get('type', ''); + $status = $this->request->get('status', ''); + + $where = []; + if ($status === '1' || $status === '0') { + $where['status'] = $status; + } + if ($type) { + switch ($type) { + case 1: + $where['hash'] = $keywords; + break; + case 2: + $where['name'] = ['like', "%{$keywords}%"]; + break; + } + } + $listObj = (new AdminAppGroup())->where($where)->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 获取全部有效的应用组 + * @author zhaoxiang + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public function getAll() { + $listInfo = (new AdminAppGroup())->where(['status' => 1])->select(); + + return $this->buildSuccess([ + 'list' => $listInfo + ]); + } + + /** + * 应用组状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminAppGroup::update([ + 'status' => $status + ], [ + 'id' => $id + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 添加应用组 + * @author zhaoxiang + * @return array + */ + public function add() { + $postData = $this->request->post(); + $res = AdminAppGroup::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 应用组编辑 + * @author zhaoxiang + * @return array + */ + public function edit() { + $postData = $this->request->post(); + $res = AdminAppGroup::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 应用组删除 + * @author zhaoxiang + * @return array + */ + public function del() { + $hash = $this->request->get('hash'); + if (!$hash) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + + $has = (new AdminApp())->where(['app_group' => $hash])->count(); + if ($has) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '当前分组存在' . $has . '个应用,禁止删除'); + } + + AdminAppGroup::destroy(['hash' => $hash]); + + return $this->buildSuccess([]); + } +} diff --git a/application/admin/controller/Auth.php b/application/admin/controller/Auth.php new file mode 100644 index 0000000..8e577d4 --- /dev/null +++ b/application/admin/controller/Auth.php @@ -0,0 +1,296 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminAuthGroup; +use app\model\AdminAuthGroupAccess; +use app\model\AdminAuthRule; +use app\model\AdminMenu; +use app\util\ReturnCode; +use app\util\Tools; + +class Auth extends Base { + + /** + * 获取权限组列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $keywords = $this->request->get('keywords', ''); + $status = $this->request->get('status', ''); + + $where['name'] = ['like', "%{$keywords}%"]; + if ($status === '1' || $status === '0') { + $where['status'] = $status; + } + $listObj = (new AdminAuthGroup())->where($where)->order('id DESC') + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 获取全部已开放的可选组 + * @author zhaoxiang + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public function getGroups() { + $listInfo = (new AdminAuthGroup())->where(['status' => 1])->order('id', 'DESC')->select(); + $count = count($listInfo); + $listInfo = Tools::buildArrFromObj($listInfo); + + return $this->buildSuccess([ + 'list' => $listInfo, + 'count' => $count + ]); + } + + /** + * 获取组所在权限列表 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function getRuleList() { + $groupId = $this->request->get('groupId', 0); + + $list = (new AdminMenu)->where([])->order('sort', 'ASC')->select(); + $list = Tools::buildArrFromObj($list); + $list = listToTree($list); + + $rules = []; + if ($groupId) { + $rules = (new AdminAuthRule())->where(['groupId' => $groupId])->select(); + $rules = Tools::buildArrFromObj($rules); + $rules = array_column($rules, 'url'); + } + $newList = $this->buildList($list, $rules); + + return $this->buildSuccess([ + 'list' => $newList + ]); + } + + /** + * 新增组 + * @return array + * @throws \Exception + * @author zhaoxiang + */ + public function add() { + $rules = []; + $postData = $this->request->post(); + if ($postData['rules']) { + $rules = $postData['rules']; + $rules = array_filter($rules); + } + unset($postData['rules']); + $res = AdminAuthGroup::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + if ($rules) { + $insertData = []; + foreach ($rules as $value) { + if ($value) { + $insertData[] = [ + 'groupId' => $res->id, + 'url' => $value + ]; + } + } + (new AdminAuthRule())->saveAll($insertData); + } + + return $this->buildSuccess([]); + } + } + + /** + * 权限组状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminAuthGroup::update([ + 'id' => $id, + 'status' => $status + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 编辑用户 + * @return array + * @throws \Exception + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function edit() { + $postData = $this->request->post(); + if ($postData['rules']) { + $this->editRule(); + } + unset($postData['rules']); + $res = AdminAuthGroup::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 删除组 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + + $listInfo = (new AdminAuthGroupAccess())->where(['groupId' => ['like', "%{$id}%"]])->select(); + if ($listInfo) { + foreach ($listInfo as $value) { + $valueArr = $value->toArray(); + $oldGroupArr = explode(',', $valueArr['groupId']); + $key = array_search($id, $oldGroupArr); + unset($oldGroupArr[$key]); + $newData = implode(',', $oldGroupArr); + $value->groupId = $newData; + $value->save(); + } + } + + AdminAuthGroup::destroy($id); + AdminAuthRule::destroy(['groupId' => $id]); + + return $this->buildSuccess([]); + } + + /** + * 从指定组中删除指定用户 + * @return array + * @throws \think\Exception + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function delMember() { + $gid = $this->request->get('gid', 0); + $uid = $this->request->get('uid', 0); + if (!$gid || !$uid) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + $oldInfo = AdminAuthGroupAccess::get(['uid' => $uid])->toArray(); + $oldGroupArr = explode(',', $oldInfo['groupId']); + $key = array_search($gid, $oldGroupArr); + unset($oldGroupArr[$key]); + $newData = implode(',', $oldGroupArr); + $res = AdminAuthGroupAccess::update([ + 'groupId' => $newData + ], [ + 'uid' => $uid + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 构建适用前端的权限数据 + * @param $list + * @param $rules + * @return array + * @author zhaoxiang + */ + private function buildList($list, $rules) { + $newList = []; + foreach ($list as $key => $value) { + $newList[$key]['title'] = $value['name']; + $newList[$key]['key'] = $value['url']; + if (isset($value['_child'])) { + $newList[$key]['expand'] = true; + $newList[$key]['children'] = $this->buildList($value['_child'], $rules); + } else { + if (in_array($value['url'], $rules)) { + $newList[$key]['checked'] = true; + } + } + } + + return $newList; + } + + /** + * 编辑权限细节 + * @throws \Exception + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @author zhaoxiang + */ + private function editRule() { + $postData = $this->request->post(); + $needAdd = []; + $has = (new AdminAuthRule())->where(['groupId' => $postData['id']])->select(); + $has = Tools::buildArrFromObj($has); + $hasRule = array_column($has, 'url'); + $needDel = array_flip($hasRule); + foreach ($postData['rules'] as $key => $value) { + if (!empty($value)) { + if (!in_array($value, $hasRule)) { + $data['url'] = $value; + $data['groupId'] = $postData['id']; + $needAdd[] = $data; + } else { + unset($needDel[$value]); + } + } + } + if (count($needAdd)) { + (new AdminAuthRule())->saveAll($needAdd); + } + if (count($needDel)) { + $urlArr = array_keys($needDel); + AdminAuthRule::destroy([ + 'groupId' => $postData['id'], + 'url' => ['in', $urlArr] + ]); + } + } + +} diff --git a/application/admin/controller/Base.php b/application/admin/controller/Base.php new file mode 100644 index 0000000..4245d49 --- /dev/null +++ b/application/admin/controller/Base.php @@ -0,0 +1,57 @@ + + */ + +namespace app\admin\controller; +use app\util\ReturnCode; +use think\Controller; + +class Base extends Controller { + + private $debug = []; + protected $userInfo; + + public function _initialize() { + $ApiAuth = $this->request->header('ApiAuth'); + if ($ApiAuth) { + $userInfo = cache('Login:' . $ApiAuth); + $this->userInfo = json_decode($userInfo, true); + } + } + + public function buildSuccess($data, $msg = '操作成功', $code = ReturnCode::SUCCESS) { + $return = [ + 'code' => $code, + 'msg' => $msg, + 'data' => $data + ]; + if ($this->debug) { + $return['debug'] = $this->debug; + } + + return $return; + } + + public function buildFailed($code, $msg, $data = []) { + $return = [ + 'code' => $code, + 'msg' => $msg, + 'data' => $data + ]; + if ($this->debug) { + $return['debug'] = $this->debug; + } + + return $return; + } + + protected function debug($data) { + if ($data) { + $this->debug[] = $data; + } + } + +} diff --git a/application/admin/controller/Fields.php b/application/admin/controller/Fields.php new file mode 100644 index 0000000..6dfc032 --- /dev/null +++ b/application/admin/controller/Fields.php @@ -0,0 +1,264 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminFields; +use app\model\AdminList; +use app\util\DataType; +use app\util\ReturnCode; +use app\util\Tools; + +class Fields extends Base { + private $dataType = array( + DataType::TYPE_INTEGER => 'Integer', + DataType::TYPE_STRING => 'String', + DataType::TYPE_BOOLEAN => 'Boolean', + DataType::TYPE_ENUM => 'Enum', + DataType::TYPE_FLOAT => 'Float', + DataType::TYPE_FILE => 'File', + DataType::TYPE_MOBILE => 'Mobile', + DataType::TYPE_OBJECT => 'Object', + DataType::TYPE_ARRAY => 'Array' + ); + + public function index() { + return $this->buildSuccess($this->dataType); + } + + /** + * 获取请求参数 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function request() { + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $hash = $this->request->get('hash', ''); + + if (!empty($hash)) { + $listObj = (new AdminFields())->where(['hash' => $hash, 'type' => 0]) + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'], + 'dataType' => $this->dataType + ]); + } else { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + } + + /** + * 获取返回参数 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function response() { + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $hash = $this->request->get('hash', ''); + + if (!empty($hash)) { + $listObj = (new AdminFields())->where(['hash' => $hash, 'type' => 1]) + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'], + 'dataType' => $this->dataType + ]); + } else { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + } + + /** + * 新增字段 + * @author zhaoxiang + * @return array + */ + public function add() { + $postData = $this->request->post(); + $postData['showName'] = $postData['fieldName']; + $postData['default'] = $postData['defaults']; + unset($postData['defaults']); + $res = AdminFields::create($postData); + + cache('RequestFields:NewRule:' . $postData['hash'], null); + cache('RequestFields:Rule:' . $postData['hash'], null); + cache('ResponseFieldsRule:' . $postData['hash'], null); + + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess('操作成功'); + } + } + + /** + * 字段编辑 + * @author zhaoxiang + * @return array + */ + public function edit() { + $postData = $this->request->post(); + $postData['showName'] = $postData['fieldName']; + $postData['default'] = $postData['defaults']; + unset($postData['defaults']); + $res = AdminFields::update($postData); + + cache('RequestFields:NewRule:' . $postData['hash'], null); + cache('RequestFields:Rule:' . $postData['hash'], null); + cache('ResponseFieldsRule:' . $postData['hash'], null); + + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 字段删除 + * @author zhaoxiang + * @return array + * @throws \think\exception\DbException + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + + $fieldsInfo = AdminFields::get($id); + cache('RequestFields:NewRule:' . $fieldsInfo->hash, null); + cache('RequestFields:Rule:' . $fieldsInfo->hash, null); + cache('ResponseFieldsRule:' . $fieldsInfo->hash, null); + + AdminFields::destroy($id); + + return $this->buildSuccess([]); + } + + /** + * 批量上传返回字段 + * @author zhaoxiang + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public function upload() { + $hash = $this->request->post('hash'); + $type = $this->request->post('type'); + $jsonStr = $this->request->post('jsonStr'); + $jsonStr = html_entity_decode($jsonStr); + $data = json_decode($jsonStr, true); + if ($data === null) { + return $this->buildFailed(ReturnCode::EXCEPTION, 'JSON数据格式有误'); + } + AdminList::update(['returnStr' => json_encode($data)], ['hash' => $hash]); + $this->handle($data['data'], $dataArr); + $old = (new AdminFields())->where([ + 'hash' => $hash, + 'type' => $type + ])->select(); + $old = Tools::buildArrFromObj($old); + $oldArr = array_column($old, 'showName'); + $newArr = array_column($dataArr, 'showName'); + $addArr = array_diff($newArr, $oldArr); + $delArr = array_diff($oldArr, $newArr); + if ($delArr) { + AdminFields::destroy(['showName' => ['in', $delArr]]); + } + if ($addArr) { + $addData = []; + foreach ($dataArr as $item) { + if (in_array($item['showName'], $addArr)) { + $addData[] = $item; + } + } + (new AdminFields())->insertAll($addData); + } + + cache('RequestFields:NewRule:' . $hash, null); + cache('RequestFields:Rule:' . $hash, null); + cache('ResponseFieldsRule:' . $hash, null); + + return $this->buildSuccess([]); + } + + private function handle($data, &$dataArr, $prefix = 'data', $index = 'data') { + if (!$this->isAssoc($data)) { + $addArr = array( + 'fieldName' => $index, + 'showName' => $prefix, + 'hash' => $this->request->post('hash'), + 'isMust' => 1, + 'dataType' => DataType::TYPE_ARRAY, + 'type' => $this->request->post('type') + ); + $dataArr[] = $addArr; + $prefix .= '[]'; + if (isset($data[0]) && is_array($data[0])) { + $this->handle($data[0], $dataArr, $prefix); + } + } else { + $addArr = array( + 'fieldName' => $index, + 'showName' => $prefix, + 'hash' => $this->request->post('hash'), + 'isMust' => 1, + 'dataType' => DataType::TYPE_OBJECT, + 'type' => $this->request->post('type') + ); + $dataArr[] = $addArr; + $prefix .= '{}'; + foreach ($data as $index => $datum) { + $myPre = $prefix . $index; + $addArr = array( + 'fieldName' => $index, + 'showName' => $myPre, + 'hash' => $this->request->post('hash'), + 'isMust' => 1, + 'dataType' => DataType::TYPE_STRING, + 'type' => $this->request->post('type') + ); + if (is_numeric($datum)) { + if (preg_match('/^\d*$/', $datum)) { + $addArr['dataType'] = DataType::TYPE_INTEGER; + } else { + $addArr['dataType'] = DataType::TYPE_FLOAT; + } + $dataArr[] = $addArr; + } elseif (is_array($datum)) { + $this->handle($datum, $dataArr, $myPre, $index); + } else { + $addArr['dataType'] = DataType::TYPE_STRING; + $dataArr[] = $addArr; + } + } + } + } + + /** + * 判断是否是关联数组(true表示是关联数组) + * @param array $arr + * @author zhaoxiang + * @return bool + */ + private function isAssoc(array $arr) { + if (array() === $arr) return false; + + return array_keys($arr) !== range(0, count($arr) - 1); + } +} diff --git a/application/admin/controller/Index.php b/application/admin/controller/Index.php new file mode 100644 index 0000000..f965292 --- /dev/null +++ b/application/admin/controller/Index.php @@ -0,0 +1,53 @@ +buildSuccess([ + 'fileName' => $new_name, + 'fileUrl' => $this->request->domain() . $path . $new_name + ]); + } else { + return $this->buildFailed(ReturnCode::FILE_SAVE_ERROR, '文件上传失败'); + } + } +} diff --git a/application/admin/controller/InterfaceGroup.php b/application/admin/controller/InterfaceGroup.php new file mode 100644 index 0000000..69357c5 --- /dev/null +++ b/application/admin/controller/InterfaceGroup.php @@ -0,0 +1,160 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminApp; +use app\model\AdminGroup; +use app\model\AdminList; +use app\util\ReturnCode; +use app\util\Tools; + +class InterfaceGroup extends Base { + /** + * 获取接口组列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $keywords = $this->request->get('keywords', ''); + $type = $this->request->get('type', ''); + $status = $this->request->get('status', ''); + + $where = []; + if ($status === '1' || $status === '0') { + $where['status'] = $status; + } + if ($type) { + switch ($type) { + case 1: + $where['hash'] = $keywords; + break; + case 2: + $where['name'] = ['like', "%{$keywords}%"]; + break; + } + } + $listObj = (new AdminGroup())->where($where)->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 获取全部有效的接口组 + * @author zhaoxiang + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public function getAll() { + $listInfo = (new AdminGroup())->where(['status' => 1])->select(); + + return $this->buildSuccess([ + 'list' => $listInfo + ]); + } + + /** + * 接口组状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminGroup::update([ + 'status' => $status + ], [ + 'id' => $id + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 添加接口组 + * @author zhaoxiang + * @return array + */ + public function add() { + $postData = $this->request->post(); + $postData['addTime'] = $postData['updateTime'] = time(); + $res = AdminGroup::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 接口组编辑 + * @author zhaoxiang + * @return array + */ + public function edit() { + $postData = $this->request->post(); + $postData['updateTime'] = time(); + $res = AdminGroup::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 接口组删除 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function del() { + $hash = $this->request->get('hash'); + if (!$hash) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + if ($hash === 'default') { + return $this->buildFailed(ReturnCode::INVALID, '系统预留关键数据,禁止删除!'); + } + + AdminList::update(['groupHash' => 'default'], ['groupHash' => $hash]); + + $hashRule = AdminApp::all([ + 'app_api_show' => ['like', "%$hash%"] + ]); + if ($hashRule) { + foreach ($hashRule as $rule) { + $appApiShowArr = json_decode($rule->app_api_show, true); + if (!empty($appApiShowArr[$hash])) { + if (isset($appApiShowArr['default'])) { + $appApiShowArr['default'] = array_merge($appApiShowArr['default'], $appApiShowArr[$hash]); + } else { + $appApiShowArr['default'] = $appApiShowArr[$hash]; + } + } + unset($appApiShowArr[$hash]); + $rule->app_api_show = json_encode($appApiShowArr); + $rule->save(); + } + } + + AdminGroup::destroy(['hash' => $hash]); + + return $this->buildSuccess([]); + } +} diff --git a/application/admin/controller/InterfaceList.php b/application/admin/controller/InterfaceList.php new file mode 100644 index 0000000..d8a7dc4 --- /dev/null +++ b/application/admin/controller/InterfaceList.php @@ -0,0 +1,194 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminApp; +use app\model\AdminFields; +use app\model\AdminList; +use app\util\ReturnCode; +use app\util\Tools; + +class InterfaceList extends Base { + /** + * 获取接口列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $keywords = $this->request->get('keywords', ''); + $type = $this->request->get('type', ''); + $status = $this->request->get('status', ''); + + $where = []; + if ($status === '1' || $status === '0') { + $where['status'] = $status; + } + if ($type) { + switch ($type) { + case 1: + $where['hash'] = $keywords; + break; + case 2: + $where['info'] = ['like', "%{$keywords}%"]; + break; + case 3: + $where['apiClass'] = ['like', "%{$keywords}%"]; + break; + } + } + $listObj = (new AdminList())->where($where)->order('id', 'DESC') + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 获取接口唯一标识 + * @author zhaoxiang + * @return array + */ + public function getHash() { + $res['hash'] = uniqid(); + + return $this->buildSuccess($res); + } + + /** + * 新增接口 + * @return array + * @author zhaoxiang + */ + public function add() { + $postData = $this->request->post(); + if (!preg_match("/^[A-Za-z0-9_\/]+$/", $postData['apiClass'])) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '真实类名只允许填写字母,数字和/'); + } + + $res = AdminList::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 接口状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $hash = $this->request->get('hash'); + $status = $this->request->get('status'); + $res = AdminList::update([ + 'status' => $status + ], [ + 'hash' => $hash + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + cache('ApiInfo:' . $hash, null); + + return $this->buildSuccess([]); + } + } + + /** + * 编辑接口 + * @return array + * @author zhaoxiang + */ + public function edit() { + $postData = $this->request->post(); + if (!preg_match("/^[A-Za-z0-9_\/]+$/", $postData['apiClass'])) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '真实类名只允许填写字母,数字和/'); + } + + $res = AdminList::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + cache('ApiInfo:' . $postData['hash'], null); + + return $this->buildSuccess([]); + } + } + + /** + * 删除接口 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function del() { + $hash = $this->request->get('hash'); + if (!$hash) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + + $hashRule = AdminApp::all([ + 'app_api' => ['like', "%$hash%"] + ]); + if ($hashRule) { + $oldInfo = AdminList::get(['hash' => $hash]); + foreach ($hashRule as $rule) { + $appApiArr = explode(',', $rule->app_api); + $appApiIndex = array_search($hash, $appApiArr); + array_splice($appApiArr, $appApiIndex, 1); + $rule->app_api = implode(',', $appApiArr); + + $appApiShowArrOld = json_decode($rule->app_api_show, true); + $appApiShowArr = $appApiShowArrOld[$oldInfo->groupHash]; + $appApiShowIndex = array_search($hash, $appApiShowArr); + array_splice($appApiShowArr, $appApiShowIndex, 1); + $appApiShowArrOld[$oldInfo->groupHash] = $appApiShowArr; + $rule->app_api_show = json_encode($appApiShowArrOld); + + $rule->save(); + } + } + + AdminList::destroy(['hash' => $hash]); + AdminFields::destroy(['hash' => $hash]); + + cache('ApiInfo:' . $hash, null); + + return $this->buildSuccess([]); + } + + /** + * 刷新接口路由 + * @author zhaoxiang + * @return array + * @throws \think\exception\DbException + */ + public function refresh() { + $apiRoutePath = ROOT_PATH . 'application/apiRoute.php'; + $tplPath = ROOT_PATH . 'data/apiRoute.tpl'; + $methodArr = ['*', 'POST', 'GET']; + + $tplStr = file_get_contents($tplPath); + $listInfo = AdminList::all(['status' => 1]); + foreach ($listInfo as $value) { + $tplStr .= 'Route::rule(\'api/' . addslashes($value->hash) . '\',\'api/' . addslashes($value->apiClass) . '\', \'' . $methodArr[$value->method] . '\', [\'after_behavior\' => $afterBehavior]);'; + } + + file_put_contents($apiRoutePath, $tplStr); + + return $this->buildSuccess([]); + } +} diff --git a/application/admin/controller/Log.php b/application/admin/controller/Log.php new file mode 100644 index 0000000..8f03461 --- /dev/null +++ b/application/admin/controller/Log.php @@ -0,0 +1,72 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminAuthGroupAccess; +use app\model\AdminUser; +use app\model\AdminUserAction; +use app\model\AdminUserData; +use app\util\ReturnCode; +use app\util\Tools; + +class Log extends Base { + + /** + * 获取操作日志列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $type = $this->request->get('type', ''); + $keywords = $this->request->get('keywords', ''); + + $where = []; + if ($type) { + switch ($type) { + case 1: + $where['url'] = ['like', "%{$keywords}%"]; + break; + case 2: + $where['nickname'] = ['like', "%{$keywords}%"]; + break; + case 3: + $where['uid'] = $keywords; + break; + } + } + $listObj = (new AdminUserAction())->where($where)->order('addTime DESC') + ->paginate($limit, false, ['page' => $start])->toArray(); + + return $this->buildSuccess([ + 'list' => $listObj['data'], + 'count' => $listObj['total'] + ]); + } + + /** + * 删除日志 + * @return array + * @author zhaoxiang + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + AdminUserAction::destroy($id); + + return $this->buildSuccess([]); + + } + +} diff --git a/application/admin/controller/Login.php b/application/admin/controller/Login.php new file mode 100644 index 0000000..d9a557c --- /dev/null +++ b/application/admin/controller/Login.php @@ -0,0 +1,101 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminAuthGroupAccess; +use app\model\AdminAuthRule; +use app\model\AdminMenu; +use app\model\AdminUser; +use app\model\AdminUserData; +use app\util\ReturnCode; +use app\util\Tools; + +class Login extends Base { + + /** + * 用户登录 + * @return array + * @throws \think\Exception + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + $username = $this->request->post('username'); + $password = $this->request->post('password'); + if (!$username) { + return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少用户名!'); + } + if (!$password) { + return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少密码!'); + } else { + $password = Tools::userMd5($password); + } + $userInfo = AdminUser::get(['username' => $username, 'password' => $password]); + if (!empty($userInfo)) { + if ($userInfo['status']) { + //更新用户数据 + $userData = AdminUserData::get(['uid' => $userInfo['id']]); + $data = []; + if ($userData) { + $userData->loginTimes ++; + $userData->lastLoginIp = $this->request->ip(1); + $userData->lastLoginTime = time(); + $return['headImg'] = $userData['headImg']; + $userData->save(); + } else { + $data['loginTimes'] = 1; + $data['uid'] = $userInfo['id']; + $data['lastLoginIp'] = $this->request->ip(1); + $data['lastLoginTime'] = time(); + $data['headImg'] = ''; + $return['headImg'] = ''; + AdminUserData::create($data); + } + } else { + return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户已被封禁,请联系管理员'); + } + } else { + return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户名密码不正确'); + } + $apiAuth = md5(uniqid() . time()); + cache('Login:' . $apiAuth, json_encode($userInfo), config('apiAdmin.ONLINE_TIME')); + cache('Login:' . $userInfo['id'], $apiAuth, config('apiAdmin.ONLINE_TIME')); + + $return['access'] = []; + $isSupper = Tools::isAdministrator($userInfo['id']); + if ($isSupper) { + $access = AdminMenu::all(['hide' => 0]); + $access = Tools::buildArrFromObj($access); + $return['access'] = array_values(array_filter(array_column($access, 'url'))); + } else { + $groups = AdminAuthGroupAccess::get(['uid' => $userInfo['id']]); + if (isset($groups) || $groups->groupId) { + $access = (new AdminAuthRule())->whereIn('groupId', $groups->groupId)->select(); + $access = Tools::buildArrFromObj($access); + $return['access'] = array_values(array_unique(array_column($access, 'url'))); + } + } + + $return['id'] = $userInfo['id']; + $return['username'] = $userInfo['username']; + $return['nickname'] = $userInfo['nickname']; + $return['apiAuth'] = $apiAuth; + + return $this->buildSuccess($return, '登录成功'); + } + + public function logout() { + $ApiAuth = $this->request->header('ApiAuth'); + cache('Login:' . $ApiAuth, null); + cache('Login:' . $this->userInfo['id'], null); + + return $this->buildSuccess([], '登出成功'); + } + +} diff --git a/application/admin/controller/Menu.php b/application/admin/controller/Menu.php new file mode 100644 index 0000000..938b2ec --- /dev/null +++ b/application/admin/controller/Menu.php @@ -0,0 +1,108 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminMenu; +use app\util\ReturnCode; +use app\util\Tools; + +class Menu extends Base { + + /** + * 获取菜单列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + $list = (new AdminMenu)->where([])->order('sort', 'ASC')->select(); + $list = Tools::buildArrFromObj($list); + $list = formatTree(listToTree($list)); + + return $this->buildSuccess([ + 'list' => $list + ], '登录成功'); + } + + /** + * 新增菜单 + * @return array + * @author zhaoxiang + */ + public function add() { + $postData = $this->request->post(); + if ($postData['url']) { + $postData['url'] = 'admin/' . $postData['url']; + } + $res = AdminMenu::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 菜单状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminMenu::update([ + 'id' => $id, + 'hide' => $status + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 编辑菜单 + * @return array + * @author zhaoxiang + */ + public function edit() { + $postData = $this->request->post(); + if ($postData['url']) { + $postData['url'] = 'admin/' . $postData['url']; + } + $res = AdminMenu::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 删除菜单 + * @return array + * @author zhaoxiang + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + $childNum = AdminMenu::where(['fid' => $id])->count(); + if ($childNum) { + return $this->buildFailed(ReturnCode::INVALID, '当前菜单存在子菜单,不可以被删除!'); + } else { + AdminMenu::destroy($id); + + return $this->buildSuccess([]); + } + } + +} diff --git a/application/admin/controller/Miss.php b/application/admin/controller/Miss.php new file mode 100644 index 0000000..4215390 --- /dev/null +++ b/application/admin/controller/Miss.php @@ -0,0 +1,15 @@ +isOptions()) { + return $this->buildSuccess([]); + } else { + return $this->buildFailed(ReturnCode::INVALID, '接口地址异常', []); + } + } +} diff --git a/application/admin/controller/User.php b/application/admin/controller/User.php new file mode 100644 index 0000000..867b31b --- /dev/null +++ b/application/admin/controller/User.php @@ -0,0 +1,269 @@ + + */ + +namespace app\admin\controller; + + +use app\model\AdminAuthGroupAccess; +use app\model\AdminUser; +use app\model\AdminUserData; +use app\util\ReturnCode; +use app\util\Tools; +use think\Db; + +class User extends Base { + + /** + * 获取用户列表 + * @return array + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $start = $this->request->get('page', 1); + $type = $this->request->get('type', ''); + $keywords = $this->request->get('keywords', ''); + $status = $this->request->get('status', ''); + + $where = []; + if ($status === '1' || $status === '0') { + $where['status'] = $status; + } + if ($type) { + switch ($type) { + case 1: + $where['username'] = ['like', "%{$keywords}%"]; + break; + case 2: + $where['nickname'] = ['like', "%{$keywords}%"]; + break; + } + } + + $listObj = (new AdminUser())->where($where)->order('regTime DESC') + ->paginate($limit, false, ['page' => $start])->toArray(); + $listInfo = $listObj['data']; + $idArr = array_column($listInfo, 'id'); + + $userData = AdminUserData::all(function($query) use ($idArr) { + $query->whereIn('uid', $idArr); + }); + $userData = Tools::buildArrFromObj($userData); + $userData = Tools::buildArrByNewKey($userData, 'uid'); + + $userGroup = AdminAuthGroupAccess::all(function($query) use ($idArr) { + $query->whereIn('uid', $idArr); + }); + $userGroup = Tools::buildArrFromObj($userGroup); + $userGroup = Tools::buildArrByNewKey($userGroup, 'uid'); + + foreach ($listInfo as $key => $value) { + if (isset($userData[$value['id']])) { + $listInfo[$key]['lastLoginIp'] = long2ip($userData[$value['id']]['lastLoginIp']); + $listInfo[$key]['loginTimes'] = $userData[$value['id']]['loginTimes']; + $listInfo[$key]['lastLoginTime'] = date('Y-m-d H:i:s', $userData[$value['id']]['lastLoginTime']); + } + $listInfo[$key]['regIp'] = long2ip($listInfo[$key]['regIp']); + if (isset($userGroup[$value['id']])) { + $listInfo[$key]['groupId'] = explode(',', $userGroup[$value['id']]['groupId']); + } else { + $listInfo[$key]['groupId'] = []; + } + } + + return $this->buildSuccess([ + 'list' => $listInfo, + 'count' => $listObj['total'] + ]); + } + + /** + * 新增用户 + * @return array + * @author zhaoxiang + */ + public function add() { + $groups = ''; + $postData = $this->request->post(); + $postData['regIp'] = request()->ip(1); + $postData['regTime'] = time(); + $postData['password'] = Tools::userMd5($postData['password']); + if ($postData['groupId']) { + $groups = trim(implode(',', $postData['groupId']), ','); + } + unset($postData['groupId']); + $res = AdminUser::create($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + AdminAuthGroupAccess::create([ + 'uid' => $res->id, + 'groupId' => $groups + ]); + + return $this->buildSuccess([]); + } + } + + /** + * 获取当前组的全部用户 + * @return array + * @throws \think\Exception + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function getUsers() { + $limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); + $page = $this->request->get('page', 1); + $gid = $this->request->get('gid', 0); + if (!$gid) { + return $this->buildFailed(ReturnCode::PARAM_INVALID, '非法操作'); + } + + $totalNum = (new AdminAuthGroupAccess())->where('find_in_set("' . $gid . '", `groupId`)')->count(); + $start = $limit * ($page - 1); + $sql = "SELECT au.* FROM admin_user as au LEFT JOIN admin_auth_group_access as aaga " . + " ON aaga.`uid` = au.`id` WHERE find_in_set('{$gid}', aaga.`groupId`) " . + " ORDER BY au.regTime DESC LIMIT {$start}, {$limit}"; + $userInfo = Db::query($sql); + + $uidArr = array_column($userInfo, 'id'); + $userData = (new AdminUserData())->whereIn('uid', $uidArr)->select(); + $userData = Tools::buildArrByNewKey($userData, 'uid'); + + foreach ($userInfo as $key => $value) { + if (isset($userData[$value['id']])) { + $userInfo[$key]['lastLoginIp'] = long2ip($userData[$value['id']]['lastLoginIp']); + $userInfo[$key]['loginTimes'] = $userData[$value['id']]['loginTimes']; + $userInfo[$key]['lastLoginTime'] = date('Y-m-d H:i:s', $userData[$value['id']]['lastLoginTime']); + } + $userInfo[$key]['regIp'] = long2ip($userInfo[$key]['regIp']); + } + + return $this->buildSuccess([ + 'list' => $userInfo, + 'count' => $totalNum + ]); + } + + /** + * 用户状态编辑 + * @return array + * @author zhaoxiang + */ + public function changeStatus() { + $id = $this->request->get('id'); + $status = $this->request->get('status'); + $res = AdminUser::update([ + 'id' => $id, + 'status' => $status, + 'updateTime' => time() + ]); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + return $this->buildSuccess([]); + } + } + + /** + * 编辑用户 + * @author zhaoxiang + * @return array + * @throws \think\exception\DbException + */ + public function edit() { + $groups = ''; + $postData = $this->request->post(); + if ($postData['password'] === 'ApiAdmin') { + unset($postData['password']); + } else { + $postData['password'] = Tools::userMd5($postData['password']); + } + if ($postData['groupId']) { + $groups = trim(implode(',', $postData['groupId']), ','); + } + $postData['updateTime'] = time(); + unset($postData['groupId']); + $res = AdminUser::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + $has = AdminAuthGroupAccess::get(['uid' => $postData['id']]); + if ($has) { + AdminAuthGroupAccess::update([ + 'groupId' => $groups + ], [ + 'uid' => $postData['id'], + ]); + } else { + AdminAuthGroupAccess::create([ + 'uid' => $postData['id'], + 'groupId' => $groups + ]); + } + + return $this->buildSuccess([]); + } + } + + /** + * 修改自己的信息 + * @author zhaoxiang + * @return array + * @throws \think\exception\DbException + */ + public function own() { + $postData = $this->request->post(); + $headImg = $postData['headImg']; + if ($postData['password'] && $postData['oldPassword']) { + $oldPass = Tools::userMd5($postData['oldPassword']); + unset($postData['oldPassword']); + if ($oldPass === $this->userInfo['password']) { + $postData['password'] = Tools::userMd5($postData['password']); + } else { + return $this->buildFailed(ReturnCode::INVALID, '原始密码不正确'); + } + } else { + unset($postData['password']); + unset($postData['oldPassword']); + } + $postData['id'] = $this->userInfo['id']; + $postData['updateTime'] = time(); + unset($postData['headImg']); + $res = AdminUser::update($postData); + if ($res === false) { + return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); + } else { + $userData = AdminUserData::get(['uid' => $postData['id']]); + $userData->headImg = $headImg; + $userData->save(); + + return $this->buildSuccess([]); + } + } + + /** + * 删除用户 + * @return array + * @author zhaoxiang + */ + public function del() { + $id = $this->request->get('id'); + if (!$id) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); + } + AdminUser::destroy($id); + AdminAuthGroupAccess::destroy(['uid' => $id]); + + return $this->buildSuccess([]); + + } + +} diff --git a/application/api/controller/Base.php b/application/api/controller/Base.php new file mode 100644 index 0000000..9fde9cd --- /dev/null +++ b/application/api/controller/Base.php @@ -0,0 +1,56 @@ + + */ + +namespace app\api\controller; + + +use app\util\ApiLog; +use app\util\ReturnCode; +use think\Controller; + +class Base extends Controller { + + private $debug = []; + protected $userInfo = []; + + public function _initialize() { + $this->userInfo = ApiLog::getUserInfo(); + } + + public function buildSuccess($data, $msg = '操作成功', $code = ReturnCode::SUCCESS) { + $return = [ + 'code' => $code, + 'msg' => $msg, + 'data' => $data + ]; + if ($this->debug) { + $return['debug'] = $this->debug; + } + + return json($return); + } + + public function buildFailed($code, $msg, $data = []) { + $return = [ + 'code' => $code, + 'msg' => $msg, + 'data' => $data + ]; + if ($this->debug) { + $return['debug'] = $this->debug; + } + + return json($return); + } + + protected function debug($data) { + if ($data) { + $this->debug[] = $data; + } + } + +} \ No newline at end of file diff --git a/application/api/controller/BuildToken.php b/application/api/controller/BuildToken.php new file mode 100644 index 0000000..73bd5c3 --- /dev/null +++ b/application/api/controller/BuildToken.php @@ -0,0 +1,90 @@ + + */ + +namespace app\api\controller; + + +use app\model\AdminApp; +use app\util\ApiLog; +use app\util\ReturnCode; +use app\util\Strs; + +class BuildToken extends Base { + + /** + * 构建AccessToken + * @return \think\response\Json + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function getAccessToken() { + $param = $this->request->param(); + if (empty($param['app_id'])) { + return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少app_id'); + } + $appInfo = (new AdminApp())->where(['app_id' => $param['app_id'], 'app_status' => 1])->find(); + if (empty($appInfo)) { + return $this->buildFailed(ReturnCode::INVALID, '应用ID非法'); + } + + $signature = $param['signature']; + unset($param['signature']); + $sign = $this->getAuthToken($appInfo['app_secret'], $param); + $this->debug($sign); + if ($sign !== $signature) { + return $this->buildFailed(ReturnCode::INVALID, '身份令牌验证失败'); + } + $expires = config('apiAdmin.ACCESS_TOKEN_TIME_OUT'); + $accessToken = cache('AccessToken:' . $param['device_id']); + if ($accessToken) { + cache('AccessToken:' . $accessToken, null); + cache('AccessToken:' . $param['device_id'], null); + } + $accessToken = $this->buildAccessToken($appInfo['app_id'], $appInfo['app_secret']); + $appInfo['device_id'] = $param['device_id']; + ApiLog::setAppInfo($appInfo); + cache('AccessToken:' . $accessToken, $appInfo, $expires); + cache('AccessToken:' . $param['device_id'], $accessToken, $expires); + $return['access_token'] = $accessToken; + $return['expires_in'] = $expires; + + return $this->buildSuccess($return); + } + + /** + * 根据AppSecret和数据生成相对应的身份认证秘钥 + * @param $appSecret + * @param $data + * @return string + */ + private function getAuthToken($appSecret, $data) { + if (empty($data)) { + return ''; + } else { + $preArr = array_merge($data, ['app_secret' => $appSecret]); + ksort($preArr); + $preStr = http_build_query($preArr); + + return md5($preStr); + } + } + + /** + * 计算出唯一的身份令牌 + * @param $appId + * @param $appSecret + * @return string + */ + private function buildAccessToken($appId, $appSecret) { + $preStr = $appSecret . $appId . time() . Strs::keyGen(); + + return md5($preStr); + } + +} diff --git a/application/api/controller/Index.php b/application/api/controller/Index.php new file mode 100644 index 0000000..3404a4c --- /dev/null +++ b/application/api/controller/Index.php @@ -0,0 +1,19 @@ +debug([ + 'TpVersion' => THINK_VERSION + ]); + + return $this->buildSuccess([ + 'Product' => config('apiAdmin.APP_NAME'), + 'Version' => config('apiAdmin.APP_VERSION'), + 'Company' => config('apiAdmin.COMPANY_NAME'), + 'ToYou' => "I'm glad to meet you(终于等到你!)" + ]); + } +} diff --git a/application/api/controller/Miss.php b/application/api/controller/Miss.php new file mode 100644 index 0000000..0d2836b --- /dev/null +++ b/application/api/controller/Miss.php @@ -0,0 +1,22 @@ +debug([ + 'TpVersion' => THINK_VERSION, + 'Float' => StrRandom::randomPhone() + ]); + + return $this->buildSuccess([ + 'Product' => config('apiAdmin.APP_NAME'), + 'Version' => config('apiAdmin.APP_VERSION'), + 'Company' => config('apiAdmin.COMPANY_NAME'), + 'ToYou' => "I'm glad to meet you(终于等到你!)" + ]); + } +} diff --git a/application/index/controller/Index.php b/application/index/controller/Index.php deleted file mode 100644 index a00d682..0000000 --- a/application/index/controller/Index.php +++ /dev/null @@ -1,15 +0,0 @@ -*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }

:)

ThinkPHP V5.1
12载初心不改(2006-2018) - 你值得信赖的PHP框架

'; - } - - public function hello($name = 'ThinkPHP5') - { - return 'hello,' . $name; - } -} diff --git a/application/model/AdminApp.php b/application/model/AdminApp.php new file mode 100644 index 0000000..5895748 --- /dev/null +++ b/application/model/AdminApp.php @@ -0,0 +1,8 @@ + + */ + +namespace app\model; + + +class AdminAppGroup extends Base { + +} diff --git a/application/model/AdminAuthGroup.php b/application/model/AdminAuthGroup.php new file mode 100644 index 0000000..285ce74 --- /dev/null +++ b/application/model/AdminAuthGroup.php @@ -0,0 +1,17 @@ + + */ + +namespace app\model; + + +class AdminAuthGroup extends Base { + + public function rules() { + return $this->hasMany('AdminAuthRule', 'groupId', 'id'); + } + +} diff --git a/application/model/AdminAuthGroupAccess.php b/application/model/AdminAuthGroupAccess.php new file mode 100644 index 0000000..94848fd --- /dev/null +++ b/application/model/AdminAuthGroupAccess.php @@ -0,0 +1,13 @@ + + */ + +namespace app\model; + + +class AdminAuthGroupAccess extends Base { + +} diff --git a/application/model/AdminAuthRule.php b/application/model/AdminAuthRule.php new file mode 100644 index 0000000..81220ae --- /dev/null +++ b/application/model/AdminAuthRule.php @@ -0,0 +1,13 @@ + + */ + +namespace app\model; + + +class AdminAuthRule extends Base { + +} diff --git a/application/model/AdminFields.php b/application/model/AdminFields.php new file mode 100644 index 0000000..fb35e66 --- /dev/null +++ b/application/model/AdminFields.php @@ -0,0 +1,12 @@ + + */ + +namespace app\model; + +class AdminFields extends Base { + +} diff --git a/application/model/AdminGroup.php b/application/model/AdminGroup.php new file mode 100644 index 0000000..59789f0 --- /dev/null +++ b/application/model/AdminGroup.php @@ -0,0 +1,13 @@ + + */ + +namespace app\model; + + +class AdminGroup extends Base { + +} diff --git a/application/model/AdminList.php b/application/model/AdminList.php new file mode 100644 index 0000000..8f78daf --- /dev/null +++ b/application/model/AdminList.php @@ -0,0 +1,11 @@ + + */ + +namespace app\model; + +class AdminList extends Base { + +} diff --git a/application/model/AdminMenu.php b/application/model/AdminMenu.php new file mode 100644 index 0000000..1f384b1 --- /dev/null +++ b/application/model/AdminMenu.php @@ -0,0 +1,8 @@ + + */ + +namespace app\model; + + +class AdminUser extends Base { + +} diff --git a/application/model/AdminUserAction.php b/application/model/AdminUserAction.php new file mode 100644 index 0000000..5dc193c --- /dev/null +++ b/application/model/AdminUserAction.php @@ -0,0 +1,13 @@ + + */ + +namespace app\model; + + +class AdminUserAction extends Base { + +} diff --git a/application/model/AdminUserData.php b/application/model/AdminUserData.php new file mode 100644 index 0000000..31a02c9 --- /dev/null +++ b/application/model/AdminUserData.php @@ -0,0 +1,12 @@ + + */ + +namespace app\model; + + +class AdminUserData extends Base { + +} diff --git a/application/model/Base.php b/application/model/Base.php new file mode 100644 index 0000000..f8c0a6d --- /dev/null +++ b/application/model/Base.php @@ -0,0 +1,15 @@ + + */ + +namespace app\model; + + +use think\Model; + +class Base extends Model { + +} diff --git a/application/util/ApiLog.php b/application/util/ApiLog.php new file mode 100644 index 0000000..65c214a --- /dev/null +++ b/application/util/ApiLog.php @@ -0,0 +1,109 @@ + + */ + +namespace app\util; + + +class ApiLog { + + private static $appInfo = 'null'; + private static $apiInfo = 'null'; + private static $request = 'null'; + private static $requestAfterFilter = 'null'; + private static $response = 'null'; + private static $header = 'null'; + private static $userInfo = 'null'; + private static $separator = '###'; + + public static function setAppInfo($data) { + self::$appInfo = + (isset($data['app_id']) ? $data['app_id'] : '') . self::$separator . + (isset($data['app_name']) ? $data['app_name'] : '') . self::$separator . + (isset($data['device_id']) ? $data['device_id'] : ''); + } + + public static function setHeader($data) { + $userToken = (isset($data['user-token']) && !empty($data['user-token'])) ? $data['user-token'] : 'null'; + $accessToken = (isset($data['access-token']) && !empty($data['access-token'])) ? $data['access-token'] : 'null'; + $version = (isset($data['version']) && !empty($data['version'])) ? $data['version'] : 'null'; + self::$header = $accessToken . self::$separator . $userToken . self::$separator . $version; + } + + public static function setApiInfo($data) { + self::$apiInfo = isset($data['apiClass']) ? $data['apiClass'] : '' . self::$separator . isset($data['hash']) ? $data['hash'] : ''; + } + + public static function setUserInfo($data) { + if (is_array($data) || is_object($data)) { + $data = json_encode($data); + } + self::$userInfo = $data; + } + + public static function getUserInfo() { + return json_decode(self::$userInfo, true); + } + + public static function setRequest($data) { + if (is_array($data) || is_object($data)) { + $data = json_encode($data); + } + self::$request = $data; + } + + public static function setRequestAfterFilter($data) { + if (is_array($data) || is_object($data)) { + $data = json_encode($data); + } + self::$requestAfterFilter = $data; + } + + public static function setResponse($data, $code = '') { + if (is_array($data) || is_object($data)) { + $data = json_encode($data); + } + self::$response = $code . self::$separator . $data; + } + + public static function save() { + $logPath = RUNTIME_PATH . 'ApiLog' . DS; + if (self::$appInfo == 'null') { + self::$appInfo = 'null' . self::$separator . 'null' . self::$separator . 'null'; + } + $logStr = implode(self::$separator, array( + self::$apiInfo, + date('Y-m-d H:i:s'), + self::$request, + self::$header, + self::$response, + self::$requestAfterFilter, + self::$appInfo, + self::$userInfo + )); + if (!file_exists($logPath)) { + mkdir($logPath, 0755, true); + } + @file_put_contents($logPath . date('YmdH') . '.log', $logStr . "\n", FILE_APPEND); + } + + + /** + * @param string $log 被记录的内容 + * @param string $type 日志文件名称 + * @param string $filePath + */ + public static function writeLog($log, $type = 'sql', $filePath = '') { + if(!$filePath) { + $filePath = '.' . DS . 'runtime' . DS; + } + $filename = $filePath . date("Ymd") . '_' . $type . ".log"; + @$handle = fopen($filename, "a+"); + @fwrite($handle, date('Y-m-d H:i:s') . "\t" . $log . "\r\n"); + @fclose($handle); + } + + +} diff --git a/application/util/BuildName.php b/application/util/BuildName.php new file mode 100644 index 0000000..ddba1ca --- /dev/null +++ b/application/util/BuildName.php @@ -0,0 +1,106 @@ + + */ + +namespace app\util; + + +class BuildName { + private $arrXing, $numbXing; + private $arrMing, $numbMing; + + function __construct() { + $this->getXingList(); + $this->getMingList(); + } + + /* 获取姓列表 */ + private function getXingList() { + $this->arrXing = [ + '赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫', '蒋', + '沈', '韩', '杨', '朱', '秦', '尤', '许', '何', '吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', + '陶', '姜', '戚', '谢', '邹', '喻', '柏', '水', '窦', '章', '云', '苏', '潘', '葛', '奚', '范', '彭', + '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '方', '任', '袁', '柳', '鲍', '史', '唐', '费', '薛', + '雷', '贺', '倪', '汤', '滕', '殷', '罗', '毕', '郝', '安', '常', '傅', '卞', '齐', '元', '顾', '孟', + '平', '黄', '穆', '萧', '尹', '姚', '邵', '湛', '汪', '祁', '毛', '狄', '米', '伏', '成', '戴', '谈', + '宋', '茅', '庞', '熊', '纪', '舒', '屈', '项', '祝', '董', '梁', '杜', '阮', '蓝', '闵', '季', '贾', + '路', '娄', '江', '童', '颜', '郭', '梅', '盛', '林', '钟', '徐', '邱', '骆', '高', '夏', '蔡', '田', + '樊', '胡', '凌', '霍', '虞', '万', '支', '柯', '管', '卢', '莫', '柯', '房', '裘', '缪', '解', '应', + '宗', '丁', '宣', '邓', '单', '杭', '洪', '包', '诸', '左', '石', '崔', '吉', '龚', '程', '嵇', '邢', + '裴', '陆', '荣', '翁', '荀', '于', '惠', '甄', '曲', '封', '储', '仲', '伊', '宁', '仇', '甘', '武', + '符', '刘', '景', '詹', '龙', '叶', '幸', '司', '黎', '溥', '印', '怀', '蒲', '邰', '从', '索', '赖', + '卓', '屠', '池', '乔', '胥', '闻', '莘', '党', '翟', '谭', '贡', '劳', '逄', '姬', '申', '扶', '堵', + '冉', '宰', '雍', '桑', '寿', '通', '燕', '浦', '尚', '农', '温', '别', '庄', '晏', '柴', '瞿', '阎', + '连', '习', '容', '向', '古', '易', '廖', '庾', '终', '步', '都', '耿', '满', '弘', '匡', '国', '文', + '寇', '广', '禄', '阙', '东', '欧', '利', '师', '巩', '聂', '关', '荆', '司马', '上官', '欧阳', '夏侯', + '诸葛', '闻人', '东方', '赫连', '皇甫', '尉迟', '公羊', '澹台', '公冶', '宗政', '濮阳', '淳于', '单于', + '太叔', '申屠', '公孙', '仲孙', '轩辕', '令狐', '徐离', '宇文', '长孙', '慕容', '司徒', '司空']; + $this->numbXing = count($this->arrXing); //姓总数 + } + + + /* 获取名列表 */ + private function getMingList() { + $this->arrMing = [ + '伟', '刚', '勇', '毅', '俊', '峰', '强', '军', '平', '保', '东', '文', '辉', '力', '明', '永', '健', '世', '广', '志', '义', + '兴', '良', '海', '山', '仁', '波', '宁', '贵', '福', '生', '龙', '元', '全', '国', '胜', '学', '祥', '才', '发', '武', '新', + '利', '清', '飞', '彬', '富', '顺', '信', '子', '杰', '涛', '昌', '成', '康', '星', '光', '天', '达', '安', '岩', '中', '茂', + '进', '林', '有', '坚', '和', '彪', '博', '诚', '先', '敬', '震', '振', '壮', '会', '思', '群', '豪', '心', '邦', '承', '乐', + '绍', '功', '松', '善', '厚', '庆', '磊', '民', '友', '裕', '河', '哲', '江', '超', '浩', '亮', '政', '谦', '亨', '奇', '固', + '之', '轮', '翰', '朗', '伯', '宏', '言', '若', '鸣', '朋', '斌', '梁', '栋', '维', '启', '克', '伦', '翔', '旭', '鹏', '泽', + '晨', '辰', '士', '以', '建', '家', '致', '树', '炎', '德', '行', '时', '泰', '盛', '雄', '琛', '钧', '冠', '策', '腾', '楠', + '榕', '风', '航', '弘', '秀', '娟', '英', '华', '慧', '巧', '美', '娜', '静', '淑', '惠', '珠', '翠', '雅', '芝', '玉', '萍', + '红', '娥', '玲', '芬', '芳', '燕', '彩', '春', '菊', '兰', '凤', '洁', '梅', '琳', '素', '云', '莲', '真', '环', '雪', '荣', + '爱', '妹', '霞', '香', '月', '莺', '媛', '艳', '瑞', '凡', '佳', '嘉', '琼', '勤', '珍', '贞', '莉', '桂', '娣', '叶', '璧', + '璐', '娅', '琦', '晶', '妍', '茜', '秋', '珊', '莎', '锦', '黛', '青', '倩', '婷', '姣', '婉', '娴', '瑾', '颖', '露', '瑶', + '怡', '婵', '雁', '蓓', '纨', '仪', '荷', '丹', '蓉', '眉', '君', '琴', '蕊', '薇', '菁', '梦', '岚', '苑', '婕', '馨', '瑗', + '琰', '韵', '融', '园', '艺', '咏', '卿', '聪', '澜', '纯', '毓', '悦', '昭', '冰', '爽', '琬', '茗', '羽', '希', '欣', '飘', + '育', '滢', '馥', '筠', '柔', '竹', '霭', '凝', '晓', '欢', '霄', '枫', '芸', '菲', '寒', '伊', '亚', '宜', '可', '姬', '舒', + '影', '荔', '枝', '丽', '阳', '妮', '宝', '贝', '初', '程', '梵', '罡', '恒', '鸿', '桦', '骅', '剑', '娇', '纪', '宽', '苛', + '灵', '玛', '媚', '琪', '晴', '容', '睿', '烁', '堂', '唯', '威', '韦', '雯', '苇', '萱', '阅', '彦', '宇', '雨', '洋', '忠', + '宗', '曼', '紫', '逸', '贤', '蝶', '菡', '绿', '蓝', '儿', '翠', '烟', '小', '轩']; + //名总数 + $this->numbMing = count($this->arrMing); + } + + + // 获取姓 + private function getXing() { + // mt_rand() 比rand()方法快四倍,而且生成的随机数比rand()生成的伪随机数无规律。 + return $this->arrXing[mt_rand(0, $this->numbXing - 1)]; + + } + + // 获取名字 + private function getMing() { + return $this->arrMing[mt_rand(0, $this->numbMing - 1)]; + } + + + // 获取名字 + public function getName($type = 2) { + switch ($type) { + case 1: //2字 + $name = $this->getXing() . $this->getMing(); + break; + case 2: //随机2、3个字 + $name = $this->getXing() . $this->getMing(); + if (mt_rand(0, 100) > 50) $name .= $this->getMing(); + break; + case 3: //只取姓 + $name = $this->getXing(); + break; + case 4: //只取名 + $name = $this->getMing(); + break; + case 0: + default: //默认情况 1姓+2名 + $name = $this->getXing() . $this->getMing() . $this->getMing(); + } + + return $name; + } +} diff --git a/application/util/DataType.php b/application/util/DataType.php new file mode 100644 index 0000000..e558302 --- /dev/null +++ b/application/util/DataType.php @@ -0,0 +1,24 @@ + + */ + +namespace app\util; + + +class DataType { + + const TYPE_INTEGER = 1; + const TYPE_STRING = 2; + const TYPE_ARRAY = 3; + const TYPE_FLOAT = 4; + const TYPE_BOOLEAN = 5; + const TYPE_FILE = 6; + const TYPE_ENUM = 7; + const TYPE_MOBILE = 8; + const TYPE_OBJECT = 9; + +} diff --git a/application/util/MockConf.php b/application/util/MockConf.php new file mode 100644 index 0000000..d2364bc --- /dev/null +++ b/application/util/MockConf.php @@ -0,0 +1,21 @@ + + */ + +namespace app\util; + + +class MockConf { + + public function mockToApiAdmin() { + + } + + public function apiAdminToMock() { + + } + +} diff --git a/application/util/ReturnCode.php b/application/util/ReturnCode.php new file mode 100644 index 0000000..781ddda --- /dev/null +++ b/application/util/ReturnCode.php @@ -0,0 +1,49 @@ + + */ + +namespace app\util; + +class ReturnCode { + + const SUCCESS = 1; + const INVALID = -1; + const DB_SAVE_ERROR = -2; + const DB_READ_ERROR = -3; + const CACHE_SAVE_ERROR = -4; + const CACHE_READ_ERROR = -5; + const FILE_SAVE_ERROR = -6; + const LOGIN_ERROR = -7; + const NOT_EXISTS = -8; + const JSON_PARSE_FAIL = -9; + const TYPE_ERROR = -10; + const NUMBER_MATCH_ERROR = -11; + const EMPTY_PARAMS = -12; + const DATA_EXISTS = -13; + const AUTH_ERROR = -14; + + const OTHER_LOGIN = -16; + const VERSION_INVALID = -17; + + const CURL_ERROR = -18; + + const RECORD_NOT_FOUND = -19; // 记录未找到 + const DELETE_FAILED = -20; // 删除失败 + const ADD_FAILED = -21; // 添加记录失败 + const UPDATE_FAILED = -22; // 添加记录失败 + + const PARAM_INVALID = -995; // 参数无效 + const ACCESS_TOKEN_TIMEOUT = -996; + const SESSION_TIMEOUT = -997; + const UNKNOWN = -998; + const EXCEPTION = -999; + + static public function getConstants() { + $oClass = new \ReflectionClass(__CLASS__); + return $oClass->getConstants(); + } + +} \ No newline at end of file diff --git a/application/util/StrRandom.php b/application/util/StrRandom.php new file mode 100644 index 0000000..97c1d71 --- /dev/null +++ b/application/util/StrRandom.php @@ -0,0 +1,186 @@ + + */ + +namespace app\util; + + +class StrRandom { + + /** + * 构建一个随机浮点数 + * @param int $min 整数部分的最小值,默认值为-999999999 + * @param int $max 整数部分的最大值,默认值为999999999 + * @param int $dmin 小数部分位数的最小值,默认值为 0 + * @param int $dmax 小数部分位数的最大值,默认值为 8 + * @return float + * @author zhaoxiang + */ + public static function randomFloat($min = -999999999, $max = 999999999, $dmin = 0, $dmax = 8) { + $rand = ''; + $intNum = mt_rand($min, $max); + $floatLength = mt_rand($dmin, $dmax); + if ($floatLength > 1) { + $rand = Strs::randString($floatLength - 1, 1); + } + $floatEnd = mt_rand(1, 9); + + return floatval($intNum . '.' . $rand . $floatEnd); + } + + /** + * 获取随机的时间 + * @param string $format PHP的时间日期格式化字符 + * @return false|string + * @author zhaoxiang + */ + public static function randomDate($format = 'Y-m-d H:i:s') { + $timestamp = time() - mt_rand(0, 86400 * 3650); + + return date($format, $timestamp); + } + + /** + * 构建随机IP地址 + * @return string + * @author zhaoxiang + */ + public static function randomIp() { + $ipLong = [ + ['607649792', '608174079'], // 36.56.0.0-36.63.255.255 + ['1038614528', '1039007743'], // 61.232.0.0-61.237.255.255 + ['1783627776', '1784676351'], // 106.80.0.0-106.95.255.255 + ['2035023872', '2035154943'], // 121.76.0.0-121.77.255.255 + ['2078801920', '2079064063'], // 123.232.0.0-123.235.255.255 + ['-1950089216', '-1948778497'], // 139.196.0.0-139.215.255.255 + ['-1425539072', '-1425014785'], // 171.8.0.0-171.15.255.255 + ['-1236271104', '-1235419137'], // 182.80.0.0-182.92.255.255 + ['-770113536', '-768606209'], // 210.25.0.0-210.47.255.255 + ['-569376768', '-564133889'], // 222.16.0.0-222.95.255.255 + ]; + $randKey = mt_rand(0, 9); + + return $ip = long2ip(mt_rand($ipLong[$randKey][0], $ipLong[$randKey][1])); + } + + /** + * 随机生成一个 URL 协议 + * @return mixed + * @author zhaoxiang + */ + public static function randomProtocol() { + $proArr = [ + 'http', + 'ftp', + 'gopher', + 'mailto', + 'mid', + 'cid', + 'news', + 'nntp', + 'prospero', + 'telnet', + 'rlogin', + 'tn3270', + 'wais' + ]; + shuffle($proArr); + + return $proArr[0]; + } + + /** + * 随机生成一个顶级域名 + * @author zhaoxiang + */ + public static function randomTld() { + $tldArr = [ + 'com', 'cn', 'xin', 'net', 'top', '在线', + 'xyz', 'wang', 'shop', 'site', 'club', 'cc', + 'fun', 'online', 'biz', 'red', 'link', 'ltd', + 'mobi', 'info', 'org', 'edu', 'com.cn', 'net.cn', + 'org.cn', 'gov.cn', 'name', 'vip', 'pro', 'work', + 'tv', 'co', 'kim', 'group', 'tech', 'store', 'ren', + 'ink', 'pub', 'live', 'wiki', 'design', '中文网', + '我爱你', '中国', '网址', '网店', '公司', '网络', '集团', 'app' + ]; + shuffle($tldArr); + + return $tldArr[0]; + } + + /** + * 获取一个随机的域名 + * @return string + * @author zhaoxiang + */ + public static function randomDomain() { + $len = mt_rand(6, 16); + + return strtolower(Strs::randString($len)) . '.' . self::randomTld(); + } + + /** + * 随机生成一个URL + * @param string $protocol 协议名称,可以不用指定 + * @return string + * @author zhaoxiang + */ + public static function randomUrl($protocol = '') { + $protocol = $protocol ? $protocol : self::randomProtocol(); + + return $protocol . '://' . self::randomDomain(); + } + + /** + * 随机生成一个邮箱地址 + * @param string $domain 可以指定邮箱域名 + * @return string + * @author zhaoxiang + */ + public static function randomEmail($domain = '') { + $len = mt_rand(6, 16); + $domain = $domain ? $domain : self::randomDomain(); + + return Strs::randString($len) . '@' . $domain; + + } + + + public static function randomPhone() { + $prefixArr = [133, 153, 173, 177, 180, 181, 189, 199, 134, 135, + 136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 172, 178, + 182, 183, 184, 187, 188, 198, 130, 131, 132, 155, 156, 166, + 175, 176, 185, 186, 145, 147, 149, 170, 171]; + shuffle($prefixArr); + + return $prefixArr[0] . Strs::randString(8, 1); + } + + /** + * 随机创建一个身份证号码 + * @return string + * @author zhaoxiang + */ + public static function randomId() { + $prefixArr = [ + 11, 12, 13, 14, 15, + 21, 22, 23, + 31, 32, 33, 34, 35, 36, 37, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, + 61, 62, 63, 64, 65, + 71, 81, 82 + ]; + shuffle($prefixArr); + + $suffixArr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'X']; + shuffle($suffixArr); + + return $prefixArr[0] . '0000' . self::randomDate('Ymd') . Strs::randString(3, 1) . $suffixArr[0]; + } + +} diff --git a/application/util/Strs.php b/application/util/Strs.php new file mode 100644 index 0000000..46b600c --- /dev/null +++ b/application/util/Strs.php @@ -0,0 +1,252 @@ + +// +---------------------------------------------------------------------- +namespace app\util; + +class Strs { + + /** + * 生成UUID 单机使用 + * @access public + * @return string + */ + static public function uuid() { + $charId = md5(uniqid(mt_rand(), true)); + $hyphen = chr(45); + $uuid = chr(123) + . substr($charId, 0, 8) . $hyphen + . substr($charId, 8, 4) . $hyphen + . substr($charId, 12, 4) . $hyphen + . substr($charId, 16, 4) . $hyphen + . substr($charId, 20, 12) + . chr(125); + + return $uuid; + } + + /** + * 生成Guid主键 + * @return Boolean + */ + static public function keyGen() { + return str_replace('-', '', substr(self::uuid(), 1, -1)); + } + + /** + * 检查字符串是否是UTF8编码 + * @param string $string 字符串 + * @return Boolean + */ + static public function isUtf8($string) { + $len = strlen($string); + for ($i = 0; $i < $len; $i++) { + $c = ord($string[$i]); + if ($c > 128) { + if (($c >= 254)) return false; + elseif ($c >= 252) $bits = 6; + elseif ($c >= 248) $bits = 5; + elseif ($c >= 240) $bits = 4; + elseif ($c >= 224) $bits = 3; + elseif ($c >= 192) $bits = 2; + else return false; + if (($i + $bits) > $len) return false; + while ($bits > 1) { + $i++; + $b = ord($string[$i]); + if ($b < 128 || $b > 191) return false; + $bits--; + } + } + } + + return true; + } + + /** + * 字符串截取,支持中文和其他编码 + * @access public + * @param string $str 需要转换的字符串 + * @param integer $start 开始位置 + * @param string $length 截取长度 + * @param string $charset 编码格式 + * @param bool $suffix 截断显示字符 + * @return string + */ + static public function mSubStr($str, $start = 0, $length, $charset = "utf-8", $suffix = true) { + if (function_exists("mb_substr")) + $slice = mb_substr($str, $start, $length, $charset); + elseif (function_exists('iconv_substr')) { + $slice = iconv_substr($str, $start, $length, $charset); + } else { + $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; + $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; + $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; + $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; + preg_match_all($re[$charset], $str, $match); + $slice = join("", array_slice($match[0], $start, $length)); + } + + return $suffix ? $slice . '...' : $slice; + } + + /** + * 产生随机字串,可用来自动生成密码 + * 默认长度6位 字母和数字混合 支持中文 + * @param integer $len 长度 + * @param string $type 字串类型 + * 0 字母 1 数字 其它 混合 + * @param string $addChars 额外字符 + * @return string + */ + static public function randString($len = 6, $type = '', $addChars = '') { + $str = ''; + switch ($type) { + case 0: + $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars; + break; + case 1: + $chars = str_repeat('0123456789', 3); + break; + case 2: + $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars; + break; + case 3: + $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars; + break; + case 4: + $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借" . $addChars; + break; + default : + // 默认去掉了容易混淆的字符oOLl和数字01,要添加请使用addChars参数 + $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars; + break; + } + if ($len > 10) {//位数过长重复字符串一定次数 + $chars = $type == 1 ? str_repeat($chars, $len) : str_repeat($chars, 5); + } + if ($type != 4) { + $chars = str_shuffle($chars); + $str = substr($chars, 0, $len); + } else { + // 中文随机字 + for ($i = 0; $i < $len; $i++) { + $str .= self::msubstr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1, 'utf-8', false); + } + } + + return $str; + } + + /** + * 生成一定数量的随机数,并且不重复 + * @param integer $number 数量 + * @param integer $length 长度 + * @param integer $mode 字串类型 + * 0 字母 1 数字 其它 混合 + * @return string + */ + static public function buildCountRand($number, $length = 4, $mode = 1) { + if ($mode == 1 && $length < strlen($number)) { + //不足以生成一定数量的不重复数字 + return false; + } + $rand = array(); + for ($i = 0; $i < $number; $i++) { + $rand[] = self::randString($length, $mode); + } + $unique = array_unique($rand); + if (count($unique) == count($rand)) { + return $rand; + } + $count = count($rand) - count($unique); + for ($i = 0; $i < $count * 3; $i++) { + $rand[] = self::randString($length, $mode); + } + $rand = array_slice(array_unique($rand), 0, $number); + + return $rand; + } + + /** + * 带格式生成随机字符 支持批量生成 + * 但可能存在重复 + * @param string $format 字符格式 + * # 表示数字 * 表示字母和数字 $ 表示字母 + * @param integer $number 生成数量 + * @return string | array + */ + static public function buildFormatRand($format, $number = 1) { + $str = array(); + $length = strlen($format); + for ($j = 0; $j < $number; $j++) { + $strTemp = ''; + for ($i = 0; $i < $length; $i++) { + $char = substr($format, $i, 1); + switch ($char) { + case "*"://字母和数字混合 + $strTemp .= self::randString(1); + break; + case "#"://数字 + $strTemp .= self::randString(1, 1); + break; + case "$"://大写字母 + $strTemp .= self::randString(1, 2); + break; + default://其他格式均不转换 + $strTemp .= $char; + break; + } + } + $str[] = $strTemp; + } + + return $number == 1 ? $strTemp : $str; + } + + /** + * 获取一定范围内的随机数字 位数不足补零 + * @param integer $min 最小值 + * @param integer $max 最大值 + * @return string + */ + static public function randNumber($min, $max) { + return sprintf("%0" . strlen($max) . "d", mt_rand($min, $max)); + } + + // 自动转换字符集 支持数组转换 + static public function autoCharset($string, $from = 'gbk', $to = 'utf-8') { + $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from; + $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to; + if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) { + //如果编码相同或者非字符串标量则不转换 + return $string; + } + if (is_string($string)) { + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($string, $to, $from); + } elseif (function_exists('iconv')) { + return iconv($from, $to, $string); + } else { + return $string; + } + } elseif (is_array($string)) { + foreach ($string as $key => $val) { + $_key = self::autoCharset($key, $from, $to); + $string[$_key] = self::autoCharset($val, $from, $to); + if ($key != $_key) + unset($string[$key]); + } + + return $string; + } else { + return $string; + } + } +} \ No newline at end of file diff --git a/application/util/Tools.php b/application/util/Tools.php new file mode 100644 index 0000000..2b62a69 --- /dev/null +++ b/application/util/Tools.php @@ -0,0 +1,115 @@ + + */ + +namespace app\util; + + +class Tools { + + public static function getDate($timestamp) { + $now = time(); + $diff = $now - $timestamp; + if ($diff <= 60) { + return $diff . '秒前'; + } elseif ($diff <= 3600) { + return floor($diff / 60) . '分钟前'; + } elseif ($diff <= 86400) { + return floor($diff / 3600) . '小时前'; + } elseif ($diff <= 2592000) { + return floor($diff / 86400) . '天前'; + } else { + return '一个月前'; + } + } + + /** + * 二次封装的密码加密 + * @param $str + * @param string $auth_key + * @return string + * @author zhaoxiang + */ + public static function userMd5($str, $auth_key = '') { + if (!$auth_key) { + $auth_key = config('apiAdmin.AUTH_KEY'); + } + + return '' === $str ? '' : md5(sha1($str) . $auth_key); + } + + /** + * 判断当前用户是否是超级管理员 + * @param string $uid + * @return bool + * @author zhaoxiang + */ + public static function isAdministrator($uid = '') { + if (!empty($uid)) { + $adminConf = config('apiAdmin.USER_ADMINISTRATOR'); + if (is_array($adminConf)) { + if (is_array($uid)) { + $m = array_intersect($adminConf, $uid); + if (count($m)) { + return true; + } + } else { + if (in_array($uid, $adminConf)) { + return true; + } + } + } else { + if (is_array($uid)) { + if (in_array($adminConf, $uid)) { + return true; + } + } else { + if ($uid == $adminConf) { + return true; + } + } + } + } + + return false; + } + + /** + * 将查询的二维对象转换成二维数组 + * @param array $res + * @param string $key 允许指定索引值 + * @return array + * @author zhaoxiang + */ + public static function buildArrFromObj($res, $key = '') { + $arr = []; + foreach ($res as $value) { + $value = $value->toArray(); + if ($key) { + $arr[$value[$key]] = $value; + } else { + $arr[] = $value; + } + } + + return $arr; + } + + /** + * 将二维数组变成指定key + * @param $array + * @param $keyName + * @author zhaoxiang + * @return array + */ + public static function buildArrByNewKey($array, $keyName = 'id') { + $list = array(); + foreach ($array as $item) { + $list[$item[$keyName]] = $item; + } + return $list; + } +} diff --git a/application/wiki/controller/Base.php b/application/wiki/controller/Base.php new file mode 100644 index 0000000..8eb1a00 --- /dev/null +++ b/application/wiki/controller/Base.php @@ -0,0 +1,90 @@ + + */ + +namespace app\wiki\controller; + + +use think\Config; +use think\Controller; +use think\exception\HttpResponseException; +use think\Request; +use think\Response; +use think\View as ViewTemplate; +use think\Url; + +class Base extends Controller { + + protected $appInfo; + + public function checkLogin() { + $appInfo = session('app_info'); + if ($appInfo) { + $this->appInfo = json_decode($appInfo, true); + } else { + $this->redirect(url('/wiki/login')); + } + } + + public function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { + if (is_null($url)) { + $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);'; + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); + } + + $type = 'html'; + $result = [ + 'code' => 0, + 'msg' => $msg, + 'data' => $data, + 'url' => $url, + 'wait' => $wait, + ]; + + if ('html' == strtolower($type)) { + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) + ->fetch(Config::get('dispatch_error_tmpl'), $result); + } + + $response = Response::create($result, $type)->header($header); + + throw new HttpResponseException($response); + } + + public function success($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { + if (is_null($url) && !is_null(Request::instance()->server('HTTP_REFERER'))) { + $url = Request::instance()->server('HTTP_REFERER'); + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); + } + + $type = 'html'; + $result = [ + 'code' => 1, + 'msg' => $msg, + 'data' => $data, + 'url' => $url, + 'wait' => $wait, + ]; + + if ('html' == strtolower($type)) { + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) + ->fetch(Config::get('dispatch_success_tmpl'), $result); + } + + $response = Response::create($result, $type)->header($header); + + throw new HttpResponseException($response); + } + +} diff --git a/application/wiki/controller/Index.php b/application/wiki/controller/Index.php new file mode 100644 index 0000000..671da98 --- /dev/null +++ b/application/wiki/controller/Index.php @@ -0,0 +1,178 @@ + + */ + +namespace app\wiki\controller; + + +use app\model\AdminApp; +use app\model\AdminFields; +use app\model\AdminGroup; +use app\model\AdminList; +use app\util\DataType; +use app\util\ReturnCode; +use app\util\Tools; + +class Index extends Base { + + /** + * 获取应用列表 + * @return \think\response\View + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function index() { + $this->checkLogin(); + + $groupInfo = AdminGroup::all(); + $groupInfo = Tools::buildArrFromObj($groupInfo); + $groupInfo = Tools::buildArrByNewKey($groupInfo, 'hash'); + + $this->appInfo = AdminApp::get(['app_id' => $this->appInfo['app_id']]); + $this->appInfo['app_api_show'] = json_decode($this->appInfo['app_api_show'], true); + + return view('', [ + 'groupInfo' => $groupInfo, + 'appInfo' => $this->appInfo + ]); + } + + public function detail() { + $this->checkLogin(); + + $groupHash = $this->request->route('groupHash'); + $hash = $this->request->route('hash', ''); + $this->appInfo['app_api_show'] = json_decode($this->appInfo['app_api_show'], true); + if (!isset($this->appInfo['app_api_show'][$groupHash]) || empty($this->appInfo['app_api_show'][$groupHash])) { + $this->error('请求非法', url('/wiki/index')); + } + + if (!$hash) { + $hash = $this->appInfo['app_api_show'][$groupHash][0]; + } else { + if (!in_array($hash, $this->appInfo['app_api_show'][$groupHash])) { + $this->error('请求非法', url('/wiki/index')); + } + } + + $apiList = (new AdminList())->whereIn('hash', $this->appInfo['app_api_show'][$groupHash])->where(['groupHash' => $groupHash])->select(); + $apiList = Tools::buildArrFromObj($apiList); + $apiList = Tools::buildArrByNewKey($apiList, 'hash'); + + if (!$hash) { + $hash = $this->appInfo['app_api_show'][$groupHash][0]; + } + $detail = $apiList[$hash]; + + $request = AdminFields::all(['hash' => $hash, 'type' => 0]); + $response = AdminFields::all(['hash' => $hash, 'type' => 1]); + $dataType = array( + DataType::TYPE_INTEGER => 'Integer', + DataType::TYPE_STRING => 'String', + DataType::TYPE_BOOLEAN => 'Boolean', + DataType::TYPE_ENUM => 'Enum', + DataType::TYPE_FLOAT => 'Float', + DataType::TYPE_FILE => 'File', + DataType::TYPE_ARRAY => 'Array', + DataType::TYPE_OBJECT => 'Object', + DataType::TYPE_MOBILE => 'Mobile' + ); + + $groupInfo = AdminGroup::get(['hash' => $groupHash]); + $groupInfo->hot = $groupInfo->hot + 1; + $groupInfo->save(); + + return view('', [ + 'groupInfo' => $groupInfo->toArray(), + 'request' => $request, + 'response' => $response, + 'dataType' => $dataType, + 'apiList' => $apiList, + 'detail' => $detail, + 'hash' => $hash, + 'groupHash' => $groupHash + ]); + } + + public function calculation() { + $this->checkLogin(); + + return view(); + } + + public function errorCode() { + $this->checkLogin(); + $codeArr = ReturnCode::getConstants(); + $errorInfo = array( + ReturnCode::SUCCESS => '请求成功', + ReturnCode::INVALID => '非法操作', + ReturnCode::DB_SAVE_ERROR => '数据存储失败', + ReturnCode::DB_READ_ERROR => '数据读取失败', + ReturnCode::CACHE_SAVE_ERROR => '缓存存储失败', + ReturnCode::CACHE_READ_ERROR => '缓存读取失败', + ReturnCode::FILE_SAVE_ERROR => '文件读取失败', + ReturnCode::LOGIN_ERROR => '登录失败', + ReturnCode::NOT_EXISTS => '不存在', + ReturnCode::JSON_PARSE_FAIL => 'JSON数据格式错误', + ReturnCode::TYPE_ERROR => '类型错误', + ReturnCode::NUMBER_MATCH_ERROR => '数字匹配失败', + ReturnCode::EMPTY_PARAMS => '丢失必要数据', + ReturnCode::DATA_EXISTS => '数据已经存在', + ReturnCode::AUTH_ERROR => '权限认证失败', + ReturnCode::OTHER_LOGIN => '别的终端登录', + ReturnCode::VERSION_INVALID => 'API版本非法', + ReturnCode::CURL_ERROR => 'CURL操作异常', + ReturnCode::RECORD_NOT_FOUND => '记录未找到', + ReturnCode::DELETE_FAILED => '删除失败', + ReturnCode::ADD_FAILED => '添加记录失败', + ReturnCode::UPDATE_FAILED => '更新记录失败', + ReturnCode::PARAM_INVALID => '数据类型非法', + ReturnCode::ACCESS_TOKEN_TIMEOUT => '身份令牌过期', + ReturnCode::SESSION_TIMEOUT => 'SESSION过期', + ReturnCode::UNKNOWN => '未知错误', + ReturnCode::EXCEPTION => '系统异常', + ); + + return view('', [ + 'errorInfo' => $errorInfo, + 'codeArr' => $codeArr + ]); + } + + public function login() { + return view(); + } + + /** + * 处理wiki登录 + * @throws \think\Exception + * @throws \think\exception\DbException + * @author zhaoxiang + */ + public function doLogin() { + $appId = $this->request->post('appId'); + $appSecret = $this->request->post('appSecret'); + + $appInfo = AdminApp::get(['app_id' => $appId, 'app_secret' => $appSecret]); + if (!empty($appInfo)) { + if ($appInfo->app_status) { + //保存用户信息和登录凭证 + session('app_info', json_encode($appInfo)); + $this->success('登录成功', url('/wiki/index')); + } else { + $this->error('当前应用已被封禁,请联系管理员'); + } + } else { + $this->error('AppId或AppSecret错误'); + } + } + + public function logout() { + session('app_info', null); + $this->success('退出成功', url('/wiki/login')); + } + +} diff --git a/application/wiki/view/index/calculation.html b/application/wiki/view/index/calculation.html new file mode 100644 index 0000000..1eab796 --- /dev/null +++ b/application/wiki/view/index/calculation.html @@ -0,0 +1,44 @@ + + + + + {:config('apiAdmin.APP_NAME')} - 算法说明 + + + +
+
+
+

{:config('apiAdmin.APP_NAME')} - 算法说明

+ + + +
+ 特别说明: 此算法文档会根据业务发展需求发生变更,为了服务的稳定运行,请及时关注此文档! +
+
+
简介
+

当前算法主要服务于获取身份令牌(AccessToken)所进行的身份认证秘钥(signature)的计算。在请求高级接口的时候,系统会验证应用的合法性,也就是验证AccessToken。所以AccessToken是请求API的必要参数。

+

在请求获取AccessToken的接口时候,服务器会对用户合法性(signature)进行核验,具体的接口请求字段,请参看具体的接口文档。

+
一、获取app_id和app_secret
+

目前获取应用ID和应用秘钥是由系统管理员发放,如果你还没有请联系管理员。请注意:app_secret非常重要请妥善保管

+
二、准备加密对象,并且根据字段名降序排序
+
//排序好后应当是如下所示的数据
+{
+    "app_id":"服务器颁发的应用ID",
+    "app_secret":"服务器颁发的应用秘钥",   //请注意,此字段只是在计算加密串的时候在被加入,API请求请勿传递此字段值
+    "device_id":"设备唯一ID",
+    "rand_str":"随机字符串",
+    "timestamp":当前系统时间戳
+}
+
三、生成原始串
+

将上面的数据构建成HTTP查询字符串,如下所示:

+

app_id=服务器颁发的应用ID&app_secret=服务器颁发的应用秘钥&device_id=设备唯一ID&rand_str=随机字符串&timestamp=当前系统时间戳

+
四、计算秘钥
+

将第三步生成的字符串进行哈希计算(md5)获得最终身份认证秘钥。

+
+

© Powered By {:config('apiAdmin.APP_NAME')} {:config('apiAdmin.APP_VERSION')}

+

+
+ + diff --git a/application/wiki/view/index/detail.html b/application/wiki/view/index/detail.html new file mode 100644 index 0000000..afa09b9 --- /dev/null +++ b/application/wiki/view/index/detail.html @@ -0,0 +1,199 @@ + + + + + {:config('apiAdmin.APP_NAME')} - 在线接口列表 + + + + + + + +
+
+
+
+
+
+ +
+
+ {$groupInfo['name']} +
+

{$groupInfo['description']}

+
+
+ 额外的细节 +
+
+
+
+
+ {php}$http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';{/php} +
接口访问地址:{$http_type}{$_SERVER['HTTP_HOST']}/api/{$hash}
+
+
+ +
+
+
+

接口唯一标识:{$hash}{if condition="$detail['isTest'] == 1"}({$detail['apiClass']}){/if}


+
+ 接口说明 + {if condition="$detail['status'] eq 0 "} + 禁用 + {else /} + {if condition="$detail['isTest'] eq 1 "} + 测试 + {else /} + 启用 + {/if} + {/if} + {:config('apiAdmin.APP_VERSION')} + + {switch name="detail['method']"} + {case value="1" break="1"}POST{/case} + {case value="2" break="1"}GET{/case} + {default /}不限 + {/switch} + +
+

{$detail['info']}

+
+
+ +
+

公共请求参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名字类型是否必须默认值其他说明
versionString必填{:config('apiAdmin.APP_VERSION')}API版本号【请在Header头里面传递】
access-tokenString{$detail['accessToken']==1?'必填':'勿填'}APP认证秘钥【请在Header头里面传递】
user-tokenString{$detail['needLogin']==1?'必填':'勿填'}用户认证秘钥【请在Header头里面传递】
+

请求参数

+ + + + + + {volist name="request" id="vo"} + + + + + + + + + {/volist} + +
参数名字类型是否必须默认值其他说明
{$vo['fieldName']}{$dataType[$vo['dataType']]}{$vo['isMust']==1?'必填':'可选'}{$vo['default']}{$vo['range']}{$vo['info']}
+
+
+

公共返回参数

+ + + + + + + + + + + + + + + + + + + + + +
返回字段类型说明
codeInteger返回码,详情请参阅错误码说明
msgString错误描述,当请求成功时可能为空
debugString调试字段,如果没有调试信息会没有此字段
+

返回参数

+ + + + + + {volist name="response" id="vo"} + + + + + + {/volist} + +
返回字段类型说明
{$vo['showName']}{$dataType[$vo['dataType']]}{$vo['info']}
+
+
+

+                
+
+ 温馨提示: 此接口参数列表根据后台代码自动生成,如有疑问请咨询后端开发 +
+

© Powered By {:config('apiAdmin.APP_NAME')} {:config('apiAdmin.APP_VERSION')}

+

+
+
+
+ + + diff --git a/application/wiki/view/index/error_code.html b/application/wiki/view/index/error_code.html new file mode 100644 index 0000000..0f40e15 --- /dev/null +++ b/application/wiki/view/index/error_code.html @@ -0,0 +1,45 @@ + + + + + {:config('apiAdmin.APP_NAME')} - 错误码说明 + + + +
+
+
+

{:config('apiAdmin.APP_NAME')} - 错误码说明

+ + + + + + + + + + + {volist name="codeArr" id="vo"} + + + + + + + {/volist} + +
#英文标识错误码中文说明
+ {$i} + + {$key} + + {$vo} + + {$errorInfo[$vo]} +
+

© Powered By {:config('apiAdmin.APP_NAME')} {:config('apiAdmin.APP_VERSION')}

+

+
+ + diff --git a/application/wiki/view/index/index.html b/application/wiki/view/index/index.html new file mode 100644 index 0000000..78db05a --- /dev/null +++ b/application/wiki/view/index/index.html @@ -0,0 +1,78 @@ + + + + + {:config('apiAdmin.APP_NAME')} - 在线接口文档 + + + +
+
+
+

{:config('apiAdmin.APP_NAME')} - 接口文档

+ + + + + + +
+
+
接口状态说明:
+

测试 系统将不过滤任何字段,也不进行AccessToken的认证,但在必要的情况下会进行UserToken的认证!

+

启用 系统将严格过滤请求字段,并且进行全部必要认证!

+

禁用 系统将拒绝所有请求,一般应用于危机处理!

+
+
+ +

© Powered By {:config('apiAdmin.APP_NAME')} {:config('apiAdmin.APP_VERSION')}

+

+
+ + diff --git a/application/wiki/view/index/login.html b/application/wiki/view/index/login.html new file mode 100644 index 0000000..86d04eb --- /dev/null +++ b/application/wiki/view/index/login.html @@ -0,0 +1,96 @@ + + + + + + + + + + + {:config('apiAdmin.APP_NAME')} - 在线接口文档 + + + + + + + + + + + +
+
+

+
+ 欢迎使用{:config('apiAdmin.APP_NAME')}在线文档 +
+

+
+
+
+
+ + +
+
+
+
+ + +
+
+
提 交
+
+
+
+
+ 如果您没有AppId和AppSecret,请联系服务供应商获取! +
+
+
+ + diff --git a/composer.json b/composer.json index fbf4410..533a7c2 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,9 @@ ], "require": { "php": ">=5.6.0", - "topthink/framework": "5.1.*" + "topthink/framework": "5.1.*", + "overtrue/pinyin": "~4.0", + "php-curl-class/php-curl-class": "^8.5" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index c63a1c0..307db7e 100644 --- a/composer.lock +++ b/composer.lock @@ -1,11 +1,138 @@ { "_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#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "296bd8a1d28e39d56dcd80ce7be249f3", + "content-hash": "18c498f30e7a274ef2d266615d3f1084", "packages": [ + { + "name": "overtrue/pinyin", + "version": "4.0.3", + "source": { + "type": "git", + "url": "https://github.com/overtrue/pinyin.git", + "reference": "b17c9c8be23e89fe3f074025b3c6bc034bfb2a90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/overtrue/pinyin/zipball/b17c9c8be23e89fe3f074025b3c6bc034bfb2a90", + "reference": "b17c9c8be23e89fe3f074025b3c6bc034bfb2a90", + "shasum": "", + "mirrors": [ + { + "url": "https://dl.laravel-china.org/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Overtrue\\Pinyin\\": "src/" + }, + "files": [ + "src/const.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carlos", + "homepage": "http://github.com/overtrue" + } + ], + "description": "Chinese to pinyin translator.", + "homepage": "https://github.com/overtrue/pinyin", + "keywords": [ + "Chinese", + "Pinyin", + "cn2pinyin" + ], + "time": "2019-04-21T14:33:59+00:00" + }, + { + "name": "php-curl-class/php-curl-class", + "version": "8.5.1", + "source": { + "type": "git", + "url": "https://github.com/php-curl-class/php-curl-class.git", + "reference": "ff95a3c56f94f3bb91e5ac6aaa94b27f39d2a2b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/ff95a3c56f94f3bb91e5ac6aaa94b27f39d2a2b1", + "reference": "ff95a3c56f94f3bb91e5ac6aaa94b27f39d2a2b1", + "shasum": "", + "mirrors": [ + { + "url": "https://dl.laravel-china.org/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-curl": "*", + "php": ">=5.3" + }, + "require-dev": { + "ext-gd": "*", + "phpunit/phpunit": "*", + "squizlabs/php_codesniffer": "*" + }, + "suggest": { + "ext-mbstring": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Curl\\": "src/Curl/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Unlicense" + ], + "authors": [ + { + "name": "Zach Borboa" + } + ], + "description": "PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs.", + "homepage": "https://github.com/php-curl-class/php-curl-class", + "keywords": [ + "API-Client", + "api", + "class", + "client", + "curl", + "framework", + "http", + "http-client", + "http-proxy", + "json", + "php", + "php-curl", + "php-curl-library", + "proxy", + "requests", + "restful", + "web-scraper", + "web-scraping ", + "web-service", + "xml" + ], + "time": "2019-04-20T05:57:47+00:00" + }, { "name": "topthink/framework", "version": "v5.1.35", @@ -18,7 +145,13 @@ "type": "zip", "url": "https://api.github.com/repos/top-think/framework/zipball/c53c0c6132022a87e8ee9c4109939eaf9a8a7adb", "reference": "c53c0c6132022a87e8ee9c4109939eaf9a8a7adb", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://dl.laravel-china.org/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.6.0", @@ -69,7 +202,13 @@ "type": "zip", "url": "https://api.github.com/repos/top-think/think-installer/zipball/f5400a12c60e513911aef41fe443fa6920952675", "reference": "f5400a12c60e513911aef41fe443fa6920952675", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://dl.laravel-china.org/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "composer-plugin-api": "^1.0" diff --git a/config/app.php b/config/app.php index 680c56c..55bda2d 100644 --- a/config/app.php +++ b/config/app.php @@ -19,7 +19,7 @@ return [ // 应用地址 'app_host' => '', // 应用调试模式 - 'app_debug' => false, + 'app_debug' => true, // 应用Trace 'app_trace' => false, // 是否支持多模块 diff --git a/config/cache.php b/config/cache.php index 985dbb1..5a4c362 100644 --- a/config/cache.php +++ b/config/cache.php @@ -15,7 +15,8 @@ return [ // 驱动方式 - 'type' => 'File', + 'type' => 'Redis', + 'host' => '127.0.0.1', // 缓存保存目录 'path' => '', // 缓存前缀 diff --git a/config/database.php b/config/database.php index d14b952..e07d3a6 100644 --- a/config/database.php +++ b/config/database.php @@ -15,11 +15,11 @@ return [ // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 - 'database' => '', + 'database' => 'apiadmin', // 用户名 'username' => 'root', // 密码 - 'password' => '', + 'password' => '123456', // 端口 'hostport' => '', // 连接dsn